From e98647820534800b10051909ee3f3c05a60039f8 Mon Sep 17 00:00:00 2001 From: BBIT-Kai <2911862937@qq.com> Date: Mon, 25 May 2026 16:16:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + app/.gitignore | 1 + app/build.gradle | 86 +++ app/proguard-rules.pro | 21 + .../com/bbit/silk/ExampleInstrumentedTest.kt | 24 + app/src/main/AndroidManifest.xml | 51 ++ app/src/main/java/com/bbit/silk/MyApp.java | 47 ++ .../java/com/bbit/silk/base/BaseComposable.kt | 432 ++++++++++++ .../java/com/bbit/silk/base/BaseViewModel.kt | 37 + .../silk/base/CustomMaterialComponents.kt | 160 +++++ .../com/bbit/silk/base/QueryComposeable.kt | 357 ++++++++++ .../java/com/bbit/silk/base/VerticalGrid.kt | 56 ++ .../main/java/com/bbit/silk/model/About.kt | 29 + .../main/java/com/bbit/silk/model/AllType.kt | 28 + app/src/main/java/com/bbit/silk/model/Auth.kt | 38 ++ .../java/com/bbit/silk/model/CheckAuth.kt | 38 ++ .../com/bbit/silk/model/CommonResponse.kt | 16 + .../main/java/com/bbit/silk/model/Login.kt | 34 + .../java/com/bbit/silk/model/QueryList.kt | 73 ++ .../java/com/bbit/silk/model/Statistics.kt | 53 ++ .../java/com/bbit/silk/model/ToConvert.kt | 22 + .../java/com/bbit/silk/model/ToTareSubmit.kt | 47 ++ .../java/com/bbit/silk/model/TodayPrice.kt | 33 + .../main/java/com/bbit/silk/model/Update.kt | 28 + .../main/java/com/bbit/silk/model/UserInfo.kt | 38 ++ .../main/java/com/bbit/silk/model/Weather.kt | 53 ++ .../com/bbit/silk/ui/activity/MainActivity.kt | 101 +++ .../com/bbit/silk/ui/screen/MainScreen.kt | 381 +++++++++++ .../ui/screen/core/ToConfirmSaleScreen.kt | 56 ++ .../silk/ui/screen/core/ToConvertScreen.kt | 41 ++ .../bbit/silk/ui/screen/core/ToTareScreen.kt | 56 ++ .../bbit/silk/ui/screen/core/TotalScreen.kt | 77 +++ .../bbit/silk/ui/screen/core/UserScreen.kt | 182 +++++ .../silk/ui/screen/coreFunc/ConvertScreen.kt | 138 ++++ .../silk/ui/screen/coreFunc/TareScreen.kt | 319 +++++++++ .../bbit/silk/ui/screen/login/AboutScreen.kt | 82 +++ .../bbit/silk/ui/screen/login/AuthScreen.kt | 161 +++++ .../bbit/silk/ui/screen/login/LoginScreen.kt | 354 ++++++++++ .../bbit/silk/ui/screen/login/UpdateScreen.kt | 86 +++ .../main/java/com/bbit/silk/ui/theme/Color.kt | 21 + .../main/java/com/bbit/silk/ui/theme/Theme.kt | 56 ++ .../main/java/com/bbit/silk/ui/theme/Type.kt | 34 + .../com/bbit/silk/ui/view/ConfirmDialog.kt | 138 ++++ .../java/com/bbit/silk/ui/view/InputDialog.kt | 128 ++++ .../com/bbit/silk/ui/view/LoadingDialog.kt | 92 +++ .../java/com/bbit/silk/ui/view/TipsDialog.kt | 93 +++ .../java/com/bbit/silk/utils/MMKVUtil.java | 129 ++++ .../main/java/com/bbit/silk/utils/MyUtil.java | 101 +++ .../silk/utils/database/AllTypeDataBase.java | 59 ++ .../silk/utils/database/PriceDataBase.java | 47 ++ .../silk/utils/database/TareDataBase.java | 88 +++ .../com/bbit/silk/utils/global/Global.java | 125 ++++ .../bbit/silk/utils/global/SpinnerList.java | 11 + .../bbit/silk/utils/log/CrashHandlerUtil.java | 61 ++ .../java/com/bbit/silk/utils/log/MyLog.java | 137 ++++ .../java/com/bbit/silk/utils/network/Url.java | 97 +++ .../bbit/silk/utils/network/XHttpManager.java | 61 ++ .../silk/utils/network/XHttpShorthand.java | 125 ++++ .../com/bbit/silk/viewmodel/AboutViewModel.kt | 44 ++ .../com/bbit/silk/viewmodel/AuthViewModel.kt | 137 ++++ .../com/bbit/silk/viewmodel/DataViewModel.kt | 294 ++++++++ .../com/bbit/silk/viewmodel/LoginViewModel.kt | 100 +++ .../com/bbit/silk/viewmodel/MainViewModel.kt | 132 ++++ .../bbit/silk/viewmodel/UpdateViewModel.kt | 148 ++++ app/src/main/java/org/xutils/DbManager.java | 233 +++++++ app/src/main/java/org/xutils/HttpManager.java | 52 ++ .../main/java/org/xutils/ImageManager.java | 32 + .../main/java/org/xutils/ViewInjector.java | 35 + .../org/xutils/cache/DiskCacheEntity.java | 129 ++++ .../java/org/xutils/cache/DiskCacheFile.java | 48 ++ .../main/java/org/xutils/cache/LruCache.java | 345 ++++++++++ .../java/org/xutils/cache/LruDiskCache.java | 391 +++++++++++ .../main/java/org/xutils/common/Callback.java | 72 ++ .../org/xutils/common/TaskController.java | 54 ++ .../java/org/xutils/common/task/AbsTask.java | 154 +++++ .../java/org/xutils/common/task/Priority.java | 9 + .../xutils/common/task/PriorityExecutor.java | 113 +++ .../xutils/common/task/PriorityRunnable.java | 23 + .../common/task/TaskControllerImpl.java | 258 +++++++ .../org/xutils/common/task/TaskProxy.java | 254 +++++++ .../org/xutils/common/util/DensityUtil.java | 44 ++ .../xutils/common/util/DoubleKeyValueMap.java | 137 ++++ .../java/org/xutils/common/util/FileUtil.java | 136 ++++ .../java/org/xutils/common/util/IOUtil.java | 127 ++++ .../java/org/xutils/common/util/KeyValue.java | 69 ++ .../java/org/xutils/common/util/LogUtil.java | 149 ++++ .../main/java/org/xutils/common/util/MD5.java | 64 ++ .../common/util/ParameterizedTypeUtil.java | 97 +++ .../org/xutils/common/util/ProcessLock.java | 234 +++++++ .../java/org/xutils/config/DbConfigs.java | 61 ++ .../main/java/org/xutils/db/CursorUtils.java | 50 ++ .../java/org/xutils/db/DbManagerImpl.java | 591 ++++++++++++++++ .../java/org/xutils/db/DbModelSelector.java | 227 ++++++ app/src/main/java/org/xutils/db/Selector.java | 248 +++++++ .../java/org/xutils/db/annotation/Column.java | 34 + .../java/org/xutils/db/annotation/Table.java | 30 + .../db/converter/BooleanColumnConverter.java | 28 + .../converter/ByteArrayColumnConverter.java | 27 + .../db/converter/ByteColumnConverter.java | 27 + .../db/converter/CharColumnConverter.java | 28 + .../xutils/db/converter/ColumnConverter.java | 19 + .../db/converter/ColumnConverterFactory.java | 108 +++ .../db/converter/DateColumnConverter.java | 30 + .../db/converter/DoubleColumnConverter.java | 27 + .../db/converter/FloatColumnConverter.java | 27 + .../db/converter/IntegerColumnConverter.java | 27 + .../db/converter/LongColumnConverter.java | 27 + .../db/converter/ShortColumnConverter.java | 27 + .../db/converter/SqlDateColumnConverter.java | 28 + .../db/converter/StringColumnConverter.java | 27 + .../org/xutils/db/sqlite/ColumnDbType.java | 20 + .../java/org/xutils/db/sqlite/SqlInfo.java | 121 ++++ .../org/xutils/db/sqlite/SqlInfoBuilder.java | 278 ++++++++ .../org/xutils/db/sqlite/WhereBuilder.java | 235 +++++++ .../org/xutils/db/table/ColumnEntity.java | 166 +++++ .../java/org/xutils/db/table/ColumnUtils.java | 179 +++++ .../main/java/org/xutils/db/table/DbBase.java | 99 +++ .../java/org/xutils/db/table/DbModel.java | 120 ++++ .../java/org/xutils/db/table/TableEntity.java | 165 +++++ .../java/org/xutils/db/table/TableUtils.java | 65 ++ .../java/org/xutils/ex/BaseException.java | 45 ++ .../main/java/org/xutils/ex/DbException.java | 35 + .../org/xutils/ex/FileLockedException.java | 12 + .../java/org/xutils/ex/HttpException.java | 81 +++ .../org/xutils/ex/HttpRedirectException.java | 25 + .../main/java/org/xutils/http/BaseParams.java | 524 ++++++++++++++ .../java/org/xutils/http/HttpManagerImpl.java | 130 ++++ .../main/java/org/xutils/http/HttpMethod.java | 46 ++ .../main/java/org/xutils/http/HttpTask.java | 645 ++++++++++++++++++ .../java/org/xutils/http/ProgressHandler.java | 14 + .../java/org/xutils/http/RequestParams.java | 407 +++++++++++ .../org/xutils/http/RequestParamsHelper.java | 116 ++++ .../xutils/http/RequestTrackerWrapper.java | 90 +++ .../xutils/http/annotation/HttpRequest.java | 39 ++ .../xutils/http/annotation/HttpResponse.java | 31 + .../xutils/http/app/DefaultParamsBuilder.java | 120 ++++ .../http/app/DefaultRedirectHandler.java | 56 ++ .../org/xutils/http/app/HttpRetryHandler.java | 76 +++ .../org/xutils/http/app/ParamsBuilder.java | 40 ++ .../org/xutils/http/app/RedirectHandler.java | 19 + .../http/app/RequestInterceptListener.java | 25 + .../org/xutils/http/app/RequestTracker.java | 35 + .../org/xutils/http/app/ResponseParser.java | 23 + .../java/org/xutils/http/body/FileBody.java | 60 ++ .../org/xutils/http/body/InputStreamBody.java | 98 +++ .../org/xutils/http/body/MultipartBody.java | 264 +++++++ .../org/xutils/http/body/ProgressBody.java | 11 + .../org/xutils/http/body/RequestBody.java | 18 + .../java/org/xutils/http/body/StringBody.java | 46 ++ .../org/xutils/http/body/UrlEncodedBody.java | 67 ++ .../org/xutils/http/cookie/CookieEntity.java | 117 ++++ .../org/xutils/http/cookie/DbCookieStore.java | 328 +++++++++ .../org/xutils/http/loader/BooleanLoader.java | 32 + .../xutils/http/loader/ByteArrayLoader.java | 42 ++ .../org/xutils/http/loader/FileLoader.java | 351 ++++++++++ .../xutils/http/loader/InputStreamLoader.java | 36 + .../org/xutils/http/loader/IntegerLoader.java | 31 + .../xutils/http/loader/JSONArrayLoader.java | 58 ++ .../xutils/http/loader/JSONObjectLoader.java | 58 ++ .../java/org/xutils/http/loader/Loader.java | 58 ++ .../org/xutils/http/loader/LoaderFactory.java | 56 ++ .../org/xutils/http/loader/ObjectLoader.java | 105 +++ .../org/xutils/http/loader/StringLoader.java | 54 ++ .../xutils/http/request/AssetsRequest.java | 31 + .../org/xutils/http/request/HttpRequest.java | 466 +++++++++++++ .../xutils/http/request/LocalFileRequest.java | 134 ++++ .../org/xutils/http/request/ResRequest.java | 175 +++++ .../org/xutils/http/request/UriRequest.java | 129 ++++ .../http/request/UriRequestFactory.java | 81 +++ .../java/org/xutils/image/AsyncDrawable.java | 221 ++++++ .../java/org/xutils/image/GifDrawable.java | 117 ++++ .../xutils/image/ImageAnimationHelper.java | 56 ++ .../java/org/xutils/image/ImageDecoder.java | 586 ++++++++++++++++ .../java/org/xutils/image/ImageLoader.java | 642 +++++++++++++++++ .../org/xutils/image/ImageManagerImpl.java | 95 +++ .../java/org/xutils/image/ImageOptions.java | 414 +++++++++++ .../java/org/xutils/image/MemCacheKey.java | 38 ++ .../xutils/image/ReusableBitmapDrawable.java | 24 + .../org/xutils/image/ReusableDrawable.java | 12 + .../org/xutils/view/EventListenerManager.java | 190 ++++++ .../main/java/org/xutils/view/ViewFinder.java | 48 ++ .../main/java/org/xutils/view/ViewInfo.java | 30 + .../org/xutils/view/ViewInjectorImpl.java | 213 ++++++ .../xutils/view/annotation/ContentView.java | 27 + .../org/xutils/view/annotation/Event.java | 48 ++ .../xutils/view/annotation/ViewInject.java | 31 + app/src/main/java/org/xutils/x.java | 131 ++++ app/src/main/res/drawable-nodpi/back.png | Bin 0 -> 695 bytes app/src/main/res/drawable-nodpi/bg_login.png | Bin 0 -> 84049 bytes app/src/main/res/drawable-nodpi/bg_main.png | Bin 0 -> 47887 bytes app/src/main/res/drawable-nodpi/bg_tare.png | Bin 0 -> 143742 bytes app/src/main/res/drawable-nodpi/bg_user.png | Bin 0 -> 143897 bytes app/src/main/res/drawable-nodpi/cancel.png | Bin 0 -> 419 bytes app/src/main/res/drawable-nodpi/check.png | Bin 0 -> 3785 bytes .../main/res/drawable-nodpi/check_success.png | Bin 0 -> 5885 bytes app/src/main/res/drawable-nodpi/date.png | Bin 0 -> 993 bytes app/src/main/res/drawable-nodpi/device.png | Bin 0 -> 2954 bytes app/src/main/res/drawable-nodpi/dismis.png | Bin 0 -> 1344 bytes app/src/main/res/drawable-nodpi/dismiss.png | Bin 0 -> 1344 bytes app/src/main/res/drawable-nodpi/down.png | Bin 0 -> 482 bytes app/src/main/res/drawable-nodpi/equal.png | Bin 0 -> 206 bytes app/src/main/res/drawable-nodpi/info.png | Bin 0 -> 4632 bytes app/src/main/res/drawable-nodpi/kinds.png | Bin 0 -> 28306 bytes app/src/main/res/drawable-nodpi/logo.png | Bin 0 -> 99105 bytes app/src/main/res/drawable-nodpi/logo_blue.png | Bin 0 -> 20260 bytes app/src/main/res/drawable-nodpi/menu.png | Bin 0 -> 365 bytes app/src/main/res/drawable-nodpi/minus.png | Bin 0 -> 187 bytes app/src/main/res/drawable-nodpi/multi.png | Bin 0 -> 348 bytes app/src/main/res/drawable-nodpi/next.png | Bin 0 -> 446 bytes app/src/main/res/drawable-nodpi/next_long.png | Bin 0 -> 568 bytes app/src/main/res/drawable-nodpi/password.png | Bin 0 -> 3467 bytes app/src/main/res/drawable-nodpi/price.png | Bin 0 -> 39921 bytes app/src/main/res/drawable-nodpi/query.png | Bin 0 -> 38005 bytes app/src/main/res/drawable-nodpi/search.png | Bin 0 -> 1473 bytes app/src/main/res/drawable-nodpi/tips.png | Bin 0 -> 2812 bytes app/src/main/res/drawable-nodpi/total.png | Bin 0 -> 37335 bytes app/src/main/res/values/colors.xml | 10 + app/src/main/res/values/strings.xml | 5 + app/src/main/res/values/themes.xml | 14 + app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 + app/src/main/res/xml/provider_paths.xml | 4 + .../java/com/bbit/silk/ExampleUnitTest.kt | 17 + build.gradle | 5 + gradle.properties | 5 + gradle/libs.versions.toml | 53 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 +++++ gradlew.bat | 89 +++ key/keystore.jks | Bin 0 -> 2500 bytes local.properties | 8 + settings.gradle | 25 + 233 files changed, 21623 insertions(+) create mode 100644 .gitignore 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/bbit/silk/ExampleInstrumentedTest.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/bbit/silk/MyApp.java create mode 100644 app/src/main/java/com/bbit/silk/base/BaseComposable.kt create mode 100644 app/src/main/java/com/bbit/silk/base/BaseViewModel.kt create mode 100644 app/src/main/java/com/bbit/silk/base/CustomMaterialComponents.kt create mode 100644 app/src/main/java/com/bbit/silk/base/QueryComposeable.kt create mode 100644 app/src/main/java/com/bbit/silk/base/VerticalGrid.kt create mode 100644 app/src/main/java/com/bbit/silk/model/About.kt create mode 100644 app/src/main/java/com/bbit/silk/model/AllType.kt create mode 100644 app/src/main/java/com/bbit/silk/model/Auth.kt create mode 100644 app/src/main/java/com/bbit/silk/model/CheckAuth.kt create mode 100644 app/src/main/java/com/bbit/silk/model/CommonResponse.kt create mode 100644 app/src/main/java/com/bbit/silk/model/Login.kt create mode 100644 app/src/main/java/com/bbit/silk/model/QueryList.kt create mode 100644 app/src/main/java/com/bbit/silk/model/Statistics.kt create mode 100644 app/src/main/java/com/bbit/silk/model/ToConvert.kt create mode 100644 app/src/main/java/com/bbit/silk/model/ToTareSubmit.kt create mode 100644 app/src/main/java/com/bbit/silk/model/TodayPrice.kt create mode 100644 app/src/main/java/com/bbit/silk/model/Update.kt create mode 100644 app/src/main/java/com/bbit/silk/model/UserInfo.kt create mode 100644 app/src/main/java/com/bbit/silk/model/Weather.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/activity/MainActivity.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/MainScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/core/ToConfirmSaleScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/core/ToConvertScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/core/ToTareScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/core/TotalScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/core/UserScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/coreFunc/ConvertScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/coreFunc/TareScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/login/AboutScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/login/AuthScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/login/LoginScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/screen/login/UpdateScreen.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/theme/Color.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/theme/Theme.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/theme/Type.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/view/ConfirmDialog.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/view/InputDialog.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/view/LoadingDialog.kt create mode 100644 app/src/main/java/com/bbit/silk/ui/view/TipsDialog.kt create mode 100644 app/src/main/java/com/bbit/silk/utils/MMKVUtil.java create mode 100644 app/src/main/java/com/bbit/silk/utils/MyUtil.java create mode 100644 app/src/main/java/com/bbit/silk/utils/database/AllTypeDataBase.java create mode 100644 app/src/main/java/com/bbit/silk/utils/database/PriceDataBase.java create mode 100644 app/src/main/java/com/bbit/silk/utils/database/TareDataBase.java create mode 100644 app/src/main/java/com/bbit/silk/utils/global/Global.java create mode 100644 app/src/main/java/com/bbit/silk/utils/global/SpinnerList.java create mode 100644 app/src/main/java/com/bbit/silk/utils/log/CrashHandlerUtil.java create mode 100644 app/src/main/java/com/bbit/silk/utils/log/MyLog.java create mode 100644 app/src/main/java/com/bbit/silk/utils/network/Url.java create mode 100644 app/src/main/java/com/bbit/silk/utils/network/XHttpManager.java create mode 100644 app/src/main/java/com/bbit/silk/utils/network/XHttpShorthand.java create mode 100644 app/src/main/java/com/bbit/silk/viewmodel/AboutViewModel.kt create mode 100644 app/src/main/java/com/bbit/silk/viewmodel/AuthViewModel.kt create mode 100644 app/src/main/java/com/bbit/silk/viewmodel/DataViewModel.kt create mode 100644 app/src/main/java/com/bbit/silk/viewmodel/LoginViewModel.kt create mode 100644 app/src/main/java/com/bbit/silk/viewmodel/MainViewModel.kt create mode 100644 app/src/main/java/com/bbit/silk/viewmodel/UpdateViewModel.kt create mode 100644 app/src/main/java/org/xutils/DbManager.java create mode 100644 app/src/main/java/org/xutils/HttpManager.java create mode 100644 app/src/main/java/org/xutils/ImageManager.java create mode 100644 app/src/main/java/org/xutils/ViewInjector.java create mode 100644 app/src/main/java/org/xutils/cache/DiskCacheEntity.java create mode 100644 app/src/main/java/org/xutils/cache/DiskCacheFile.java create mode 100644 app/src/main/java/org/xutils/cache/LruCache.java create mode 100644 app/src/main/java/org/xutils/cache/LruDiskCache.java create mode 100644 app/src/main/java/org/xutils/common/Callback.java create mode 100644 app/src/main/java/org/xutils/common/TaskController.java create mode 100644 app/src/main/java/org/xutils/common/task/AbsTask.java create mode 100644 app/src/main/java/org/xutils/common/task/Priority.java create mode 100644 app/src/main/java/org/xutils/common/task/PriorityExecutor.java create mode 100644 app/src/main/java/org/xutils/common/task/PriorityRunnable.java create mode 100644 app/src/main/java/org/xutils/common/task/TaskControllerImpl.java create mode 100644 app/src/main/java/org/xutils/common/task/TaskProxy.java create mode 100644 app/src/main/java/org/xutils/common/util/DensityUtil.java create mode 100644 app/src/main/java/org/xutils/common/util/DoubleKeyValueMap.java create mode 100644 app/src/main/java/org/xutils/common/util/FileUtil.java create mode 100644 app/src/main/java/org/xutils/common/util/IOUtil.java create mode 100644 app/src/main/java/org/xutils/common/util/KeyValue.java create mode 100644 app/src/main/java/org/xutils/common/util/LogUtil.java create mode 100644 app/src/main/java/org/xutils/common/util/MD5.java create mode 100644 app/src/main/java/org/xutils/common/util/ParameterizedTypeUtil.java create mode 100644 app/src/main/java/org/xutils/common/util/ProcessLock.java create mode 100644 app/src/main/java/org/xutils/config/DbConfigs.java create mode 100644 app/src/main/java/org/xutils/db/CursorUtils.java create mode 100644 app/src/main/java/org/xutils/db/DbManagerImpl.java create mode 100644 app/src/main/java/org/xutils/db/DbModelSelector.java create mode 100644 app/src/main/java/org/xutils/db/Selector.java create mode 100644 app/src/main/java/org/xutils/db/annotation/Column.java create mode 100644 app/src/main/java/org/xutils/db/annotation/Table.java create mode 100644 app/src/main/java/org/xutils/db/converter/BooleanColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/ByteArrayColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/ByteColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/CharColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/ColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/ColumnConverterFactory.java create mode 100644 app/src/main/java/org/xutils/db/converter/DateColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/DoubleColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/FloatColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/IntegerColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/LongColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/ShortColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/SqlDateColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/converter/StringColumnConverter.java create mode 100644 app/src/main/java/org/xutils/db/sqlite/ColumnDbType.java create mode 100644 app/src/main/java/org/xutils/db/sqlite/SqlInfo.java create mode 100644 app/src/main/java/org/xutils/db/sqlite/SqlInfoBuilder.java create mode 100644 app/src/main/java/org/xutils/db/sqlite/WhereBuilder.java create mode 100644 app/src/main/java/org/xutils/db/table/ColumnEntity.java create mode 100644 app/src/main/java/org/xutils/db/table/ColumnUtils.java create mode 100644 app/src/main/java/org/xutils/db/table/DbBase.java create mode 100644 app/src/main/java/org/xutils/db/table/DbModel.java create mode 100644 app/src/main/java/org/xutils/db/table/TableEntity.java create mode 100644 app/src/main/java/org/xutils/db/table/TableUtils.java create mode 100644 app/src/main/java/org/xutils/ex/BaseException.java create mode 100644 app/src/main/java/org/xutils/ex/DbException.java create mode 100644 app/src/main/java/org/xutils/ex/FileLockedException.java create mode 100644 app/src/main/java/org/xutils/ex/HttpException.java create mode 100644 app/src/main/java/org/xutils/ex/HttpRedirectException.java create mode 100644 app/src/main/java/org/xutils/http/BaseParams.java create mode 100644 app/src/main/java/org/xutils/http/HttpManagerImpl.java create mode 100644 app/src/main/java/org/xutils/http/HttpMethod.java create mode 100644 app/src/main/java/org/xutils/http/HttpTask.java create mode 100644 app/src/main/java/org/xutils/http/ProgressHandler.java create mode 100644 app/src/main/java/org/xutils/http/RequestParams.java create mode 100644 app/src/main/java/org/xutils/http/RequestParamsHelper.java create mode 100644 app/src/main/java/org/xutils/http/RequestTrackerWrapper.java create mode 100644 app/src/main/java/org/xutils/http/annotation/HttpRequest.java create mode 100644 app/src/main/java/org/xutils/http/annotation/HttpResponse.java create mode 100644 app/src/main/java/org/xutils/http/app/DefaultParamsBuilder.java create mode 100644 app/src/main/java/org/xutils/http/app/DefaultRedirectHandler.java create mode 100644 app/src/main/java/org/xutils/http/app/HttpRetryHandler.java create mode 100644 app/src/main/java/org/xutils/http/app/ParamsBuilder.java create mode 100644 app/src/main/java/org/xutils/http/app/RedirectHandler.java create mode 100644 app/src/main/java/org/xutils/http/app/RequestInterceptListener.java create mode 100644 app/src/main/java/org/xutils/http/app/RequestTracker.java create mode 100644 app/src/main/java/org/xutils/http/app/ResponseParser.java create mode 100644 app/src/main/java/org/xutils/http/body/FileBody.java create mode 100644 app/src/main/java/org/xutils/http/body/InputStreamBody.java create mode 100644 app/src/main/java/org/xutils/http/body/MultipartBody.java create mode 100644 app/src/main/java/org/xutils/http/body/ProgressBody.java create mode 100644 app/src/main/java/org/xutils/http/body/RequestBody.java create mode 100644 app/src/main/java/org/xutils/http/body/StringBody.java create mode 100644 app/src/main/java/org/xutils/http/body/UrlEncodedBody.java create mode 100644 app/src/main/java/org/xutils/http/cookie/CookieEntity.java create mode 100644 app/src/main/java/org/xutils/http/cookie/DbCookieStore.java create mode 100644 app/src/main/java/org/xutils/http/loader/BooleanLoader.java create mode 100644 app/src/main/java/org/xutils/http/loader/ByteArrayLoader.java create mode 100644 app/src/main/java/org/xutils/http/loader/FileLoader.java create mode 100644 app/src/main/java/org/xutils/http/loader/InputStreamLoader.java create mode 100644 app/src/main/java/org/xutils/http/loader/IntegerLoader.java create mode 100644 app/src/main/java/org/xutils/http/loader/JSONArrayLoader.java create mode 100644 app/src/main/java/org/xutils/http/loader/JSONObjectLoader.java create mode 100644 app/src/main/java/org/xutils/http/loader/Loader.java create mode 100644 app/src/main/java/org/xutils/http/loader/LoaderFactory.java create mode 100644 app/src/main/java/org/xutils/http/loader/ObjectLoader.java create mode 100644 app/src/main/java/org/xutils/http/loader/StringLoader.java create mode 100644 app/src/main/java/org/xutils/http/request/AssetsRequest.java create mode 100644 app/src/main/java/org/xutils/http/request/HttpRequest.java create mode 100644 app/src/main/java/org/xutils/http/request/LocalFileRequest.java create mode 100644 app/src/main/java/org/xutils/http/request/ResRequest.java create mode 100644 app/src/main/java/org/xutils/http/request/UriRequest.java create mode 100644 app/src/main/java/org/xutils/http/request/UriRequestFactory.java create mode 100644 app/src/main/java/org/xutils/image/AsyncDrawable.java create mode 100644 app/src/main/java/org/xutils/image/GifDrawable.java create mode 100644 app/src/main/java/org/xutils/image/ImageAnimationHelper.java create mode 100644 app/src/main/java/org/xutils/image/ImageDecoder.java create mode 100644 app/src/main/java/org/xutils/image/ImageLoader.java create mode 100644 app/src/main/java/org/xutils/image/ImageManagerImpl.java create mode 100644 app/src/main/java/org/xutils/image/ImageOptions.java create mode 100644 app/src/main/java/org/xutils/image/MemCacheKey.java create mode 100644 app/src/main/java/org/xutils/image/ReusableBitmapDrawable.java create mode 100644 app/src/main/java/org/xutils/image/ReusableDrawable.java create mode 100644 app/src/main/java/org/xutils/view/EventListenerManager.java create mode 100644 app/src/main/java/org/xutils/view/ViewFinder.java create mode 100644 app/src/main/java/org/xutils/view/ViewInfo.java create mode 100644 app/src/main/java/org/xutils/view/ViewInjectorImpl.java create mode 100644 app/src/main/java/org/xutils/view/annotation/ContentView.java create mode 100644 app/src/main/java/org/xutils/view/annotation/Event.java create mode 100644 app/src/main/java/org/xutils/view/annotation/ViewInject.java create mode 100644 app/src/main/java/org/xutils/x.java create mode 100644 app/src/main/res/drawable-nodpi/back.png create mode 100644 app/src/main/res/drawable-nodpi/bg_login.png create mode 100644 app/src/main/res/drawable-nodpi/bg_main.png create mode 100644 app/src/main/res/drawable-nodpi/bg_tare.png create mode 100644 app/src/main/res/drawable-nodpi/bg_user.png create mode 100644 app/src/main/res/drawable-nodpi/cancel.png create mode 100644 app/src/main/res/drawable-nodpi/check.png create mode 100644 app/src/main/res/drawable-nodpi/check_success.png create mode 100644 app/src/main/res/drawable-nodpi/date.png create mode 100644 app/src/main/res/drawable-nodpi/device.png create mode 100644 app/src/main/res/drawable-nodpi/dismis.png create mode 100644 app/src/main/res/drawable-nodpi/dismiss.png create mode 100644 app/src/main/res/drawable-nodpi/down.png create mode 100644 app/src/main/res/drawable-nodpi/equal.png create mode 100644 app/src/main/res/drawable-nodpi/info.png create mode 100644 app/src/main/res/drawable-nodpi/kinds.png create mode 100644 app/src/main/res/drawable-nodpi/logo.png create mode 100644 app/src/main/res/drawable-nodpi/logo_blue.png create mode 100644 app/src/main/res/drawable-nodpi/menu.png create mode 100644 app/src/main/res/drawable-nodpi/minus.png create mode 100644 app/src/main/res/drawable-nodpi/multi.png create mode 100644 app/src/main/res/drawable-nodpi/next.png create mode 100644 app/src/main/res/drawable-nodpi/next_long.png create mode 100644 app/src/main/res/drawable-nodpi/password.png create mode 100644 app/src/main/res/drawable-nodpi/price.png create mode 100644 app/src/main/res/drawable-nodpi/query.png create mode 100644 app/src/main/res/drawable-nodpi/search.png create mode 100644 app/src/main/res/drawable-nodpi/tips.png create mode 100644 app/src/main/res/drawable-nodpi/total.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/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/main/res/xml/provider_paths.xml create mode 100644 app/src/test/java/com/bbit/silk/ExampleUnitTest.kt create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml 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 key/keystore.jks create mode 100644 local.properties create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d4fcda --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.gradle/ +.idea/ +app/release/ diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..643222f --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,86 @@ +plugins { + alias(libs.plugins.androidApplication) + alias(libs.plugins.jetbrainsKotlinAndroid) + id 'kotlin-parcelize' +} + +android { + namespace 'com.bbit.silk' + compileSdk 34 + + defaultConfig { + applicationId "com.bbit.silk" + minSdk 22 + targetSdk 34 + versionCode 22 + versionName "2.0.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = '17' + } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion '1.5.5' + } + packaging { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +dependencies { + + implementation libs.androidx.core.ktx + implementation libs.androidx.lifecycle.runtime.ktx + implementation libs.androidx.activity.compose + implementation platform(libs.androidx.compose.bom) + implementation libs.androidx.ui + implementation libs.androidx.ui.graphics + implementation libs.androidx.ui.tooling.preview + implementation libs.androidx.material3 + implementation libs.androidx.core.splashscreen + testImplementation libs.junit + androidTestImplementation libs.androidx.junit + androidTestImplementation libs.androidx.espresso.core + androidTestImplementation platform(libs.androidx.compose.bom) + androidTestImplementation libs.androidx.ui.test.junit4 + debugImplementation libs.androidx.ui.tooling + debugImplementation libs.androidx.ui.test.manifest + //lifecycle-viewmodel-compose + implementation libs.androidx.lifecycle.viewmodel.compose + implementation libs.androidx.material.icons.extended + //MMKV + implementation libs.mmkv + //util + implementation libs.com.blankj.utilcodex2 + //GSON + implementation libs.com.google.code.gson.gson2 + //权限库 + implementation libs.com.github.getactivity.xxpermissions + //日志库 + implementation libs.timber + implementation libs.androidx.legacy.legacy.support.v43 + implementation libs.androidx.navigation.compose + //日期下拉框 + implementation libs.android.pickerview + implementation libs.ltttttttttttt.composeviews +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /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 \ No newline at end of file diff --git a/app/src/androidTest/java/com/bbit/silk/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/bbit/silk/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..489030f --- /dev/null +++ b/app/src/androidTest/java/com/bbit/silk/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.bbit.silk + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.bbit.silk", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9338c72 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/MyApp.java b/app/src/main/java/com/bbit/silk/MyApp.java new file mode 100644 index 0000000..93a5c78 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/MyApp.java @@ -0,0 +1,47 @@ +package com.bbit.silk; + +import android.app.Application; +import android.content.Context; +import android.provider.Settings; + +import com.bbit.silk.utils.MMKVUtil; +import com.bbit.silk.utils.global.Global; +import com.bbit.silk.utils.log.CrashHandlerUtil; +import com.bbit.silk.utils.log.MyLog; +import com.bbit.silk.utils.network.Url; +import com.tencent.mmkv.MMKV; + +import org.xutils.x; + +import timber.log.Timber; + +/** + * @Description APPLICATION类 + * @Author DuanKaiji + * @CreateTime 2024年03月27日 13:43 + */ +public class MyApp extends Application { + private static MyApp instance; + + @Override + public void onCreate() { + super.onCreate(); + instance = this; + // 初始化网络请求地址 + Url.initUrl(); + // 初始化MMKV + MMKV.initialize(getApplicationContext()); + MMKVUtil.init(); + // 初始化崩溃捕捉 + CrashHandlerUtil.getInstance().init(getApplicationContext()); + // 初始化日志库 + Timber.plant(new MyLog()); + // 初始化网络请求库 + x.Ext.init(this); + MMKVUtil.put(Global.DEVICE_ID, Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID)); + } + + public static Context getAppContext() { + return instance.getApplicationContext(); + } +} diff --git a/app/src/main/java/com/bbit/silk/base/BaseComposable.kt b/app/src/main/java/com/bbit/silk/base/BaseComposable.kt new file mode 100644 index 0000000..82d1ca9 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/base/BaseComposable.kt @@ -0,0 +1,432 @@ +package com.bbit.silk.base + +import BaseViewModel +import androidx.compose.animation.animateContentSize +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Tab +import androidx.compose.material3.TabRow +import androidx.compose.material3.TabRowDefaults +import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarDefaults.enterAlwaysScrollBehavior +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.myapplication.ui.theme.MyColors +import com.bbit.silk.ui.view.LoadingDialog +import com.bbit.silk.ui.view.TipsDialog +import com.bbit.silk.viewmodel.DataViewModel +import com.blankj.utilcode.constant.TimeConstants +import com.blankj.utilcode.util.TimeUtils +import com.lt.compose_views.refresh_layout.RefreshContentStateEnum +import com.lt.compose_views.refresh_layout.VerticalRefreshableLayout +import com.lt.compose_views.refresh_layout.rememberRefreshLayoutState +import kotlinx.coroutines.launch + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年05月06日 10:24:24 + */ +@Preview(showBackground = true, widthDp = 300) +@Composable +fun ContentFramePreview() { + ContentFrame( + title = "标题", + content = { + Text(text = "内容") + } + ) +} + +@Composable +fun ContentFrame( + title: String, + buttonTitle: String? = null, + buttonClick: (() -> Unit)? = null, + content: @Composable () -> Unit, +) { + MyCard(modifier = Modifier.padding(10.dp)) { + Column { + Row( + modifier = Modifier + .padding( + horizontal = 10.dp, + vertical = if (buttonTitle == null) 12.5.dp else 0.dp + ) + .fillMaxWidth() + ) { + Box( + modifier = Modifier + .width(3.dp) + .heightIn(max = 25.dp) + .align(Alignment.CenterVertically) + .fillMaxHeight() + .background(Color(0xFF209344)) + ) + Text( + text = title, + modifier = Modifier + .wrapContentHeight() + .padding(start = 10.dp) + .align(Alignment.CenterVertically) + ) + if (buttonTitle != null && buttonClick != null) { + Spacer(modifier = Modifier.weight(1f)) + OutlinedButton( + modifier = Modifier + .padding(0.dp) + .align(Alignment.CenterVertically) + .heightIn(20.dp), + onClick = { buttonClick() }) { + Text(text = buttonTitle) + } + } + } + Divider( + color = Color.LightGray, // 分割线颜色 + thickness = 1.dp, // 分割线厚度 + ) + Box( + modifier = Modifier + .padding(10.dp) + .fillMaxWidth() + .animateContentSize( + animationSpec = spring( + dampingRatio = Spring.DampingRatioMediumBouncy, + stiffness = Spring.StiffnessLow + ) + ) + ) { + content() + } + } + } +} + +@Preview(showBackground = true, widthDp = 300) +@Composable +fun MainFramePreview() { + MainFrame( + Modifier, + "测试页面", + navController = rememberNavController(), + presenter = BaseViewModel(), + content = { + + }) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MainFrame( + modifier: Modifier = Modifier, + title: String, + presenter: BaseViewModel, + navController: NavController, + content: @Composable () -> Unit, +) { +// val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) + val scrollBehavior =TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) + TipsDialog( + showDialog = presenter.tipsDialog.collectAsState().value.showDialog, + onDismiss = { presenter.hideTipsDialog() }, + content = presenter.tipsDialog.collectAsState().value.content + ) + LoadingDialog(presenter.loadingDialog.collectAsState().value) + Scaffold( + topBar = { + CenterAlignedTopAppBar( + title = { + Text( + title, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + }, + navigationIcon = { + IconButton(onClick = { navController.popBackStack() }) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = "Localized description" + ) + } + }, + scrollBehavior = scrollBehavior, + ) + } + ) { innerPadding -> + Column( + modifier = modifier + .padding(innerPadding) + .fillMaxWidth() + ) { + Divider() + content() + } + } +} + +@Preview(showBackground = true) +@Composable +fun BaseDoubleTextFieldPreView() { + BaseDoubleTextField(title = "企业编号") { } +} + +@Composable +fun BaseDoubleTextField( + title: String, + startIcon: Int? = null, + justShowStr: String? = null, + inputDefaultValue: String = "", + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onClick: () -> Unit = {}, + onContentChange: (String) -> Unit = {} +) { + var content by rememberSaveable { mutableStateOf(inputDefaultValue) } + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 2.dp) + .heightIn(min = 40.dp) + .noVisualFeedbackClickable { onClick() } + ) { + if (startIcon != null) { + Icon( + modifier = Modifier + .padding(start = 3.dp) + .size(15.dp) + .align(Alignment.CenterVertically), + painter = painterResource(id = startIcon), + contentDescription = "Localized description" + ) + } + Text( + text = title, + modifier = Modifier + .padding(start = (if (startIcon == null) 20.dp else 2.5.dp)) + .weight(9f) + .align(Alignment.CenterVertically) + ) + if (justShowStr != null) { + Text( + text = justShowStr, + modifier = Modifier + .padding(end = 15.dp) + .weight(12f) + .align(Alignment.CenterVertically), + textAlign = TextAlign.End + ) + } else { + MyTextField( + value = content, + modifier = Modifier + .weight(10f) + .padding(end = 15.dp) + .widthIn(200.dp), + keyboardOptions = keyboardOptions, + onValueChange = { + content = it + onContentChange(it) + }, + textStyle = TextStyle(textAlign = TextAlign.End) + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun BaseQueryScreenPreView() { + BaseQueryScreen( + queryType = 1, + onItemClick = { + + } + ) +} + +@Composable +fun BaseQueryScreen( + queryType: Int, + showCancel: Boolean = false, + showConfirm: Boolean = false, + presenter: DataViewModel = viewModel(), + onItemClick: ((Any) -> Unit) = { } +) { + val data = presenter.queryList.collectAsState().value + var curPage by remember { mutableStateOf(1) } + val startDate = + TimeUtils.date2String(TimeUtils.getDateByNow(-31, TimeConstants.DAY), "yyyy-MM-dd") + val endDate = TimeUtils.date2String(TimeUtils.getNowDate(), "yyyy-MM-dd") + val isLoadFinish = presenter.isFinish.collectAsState().value + val refreshState = rememberRefreshLayoutState { + setRefreshState(RefreshContentStateEnum.Refreshing) + curPage = 1 + presenter.queryData(queryType, startDate, endDate, page = curPage) + } + val loadMoreState = rememberRefreshLayoutState { + curPage += 1 + presenter.queryData(queryType, startDate, endDate, page = curPage) + } + val isLoading = presenter.isLoading.collectAsState().value + LaunchedEffect(Unit) { + // 初始加载数据 + refreshState.setRefreshState(RefreshContentStateEnum.Refreshing) + presenter.queryData(queryType, startDate, endDate) + } + LaunchedEffect(isLoading) { + if (!isLoading) { + // 监听加载状态,停止刷新 + refreshState.setRefreshState(RefreshContentStateEnum.Stop) + loadMoreState.setRefreshState(RefreshContentStateEnum.Stop) + } + } + Column { + BaseQueryByDate(startDate, endDate, true) { startDate, endDate, key -> + refreshState.setRefreshState(RefreshContentStateEnum.Refreshing) + curPage = 1 + presenter.queryData(queryType, startDate, endDate, key) + } + VerticalRefreshableLayout( + modifier = Modifier.fillMaxWidth(), + topRefreshLayoutState = refreshState, + bottomRefreshLayoutState = loadMoreState, + bottomIsLoadFinish = isLoadFinish + ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { + if (data.isNotEmpty()) { + items(data) { + ItemData( + name = it.nhName, + id = it.czCode, + state = it.status, + data = it.items, + showCancel = showCancel, + showConfirm = showConfirm, + czsysid = it.czSysid + ) { + onItemClick(it) + } + } + } else { + item { NoData() } + } + } + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun BaseFixedTabRow( + modifier: Modifier = Modifier, + tabData: List Unit>>, +) { + val rememberedContent = remember { tabData } + val coroutineScope = rememberCoroutineScope() + val pagerState = rememberPagerState(pageCount = { tabData.size }) + Column(modifier = modifier.fillMaxSize()) { + // 选项卡行 + TabRow( + selectedTabIndex = pagerState.currentPage, + indicator = { tabPositions -> + TabRowDefaults.Indicator( + modifier = Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage]), + color = MyColors.Green + ) + }, + ) { + tabData.forEachIndexed { index, pair -> + val (title, _) = pair + Tab( + selected = pagerState.currentPage == index, + onClick = { + coroutineScope.launch { + pagerState.animateScrollToPage(index) + } + }, + text = { Text(text = title) }, + selectedContentColor = MyColors.Green, + unselectedContentColor = if (isSystemInDarkTheme()) Color.LightGray else Color.Black + ) + } + } + // 选中选项卡的内容 + HorizontalPager(state = pagerState, modifier = Modifier.fillMaxSize(), userScrollEnabled = false, beyondBoundsPageCount = 2) { selectedTabIndex -> + rememberedContent[selectedTabIndex].second() + } + } +} + +/** + * 自定义点击事件 + * 不使用clickable的点击效果 + */ +fun Modifier.noVisualFeedbackClickable( + onClick: () -> Unit +): Modifier { + return this.pointerInput(Unit) { + detectTapGestures( + onTap = { + onClick() + } + ) + } +} diff --git a/app/src/main/java/com/bbit/silk/base/BaseViewModel.kt b/app/src/main/java/com/bbit/silk/base/BaseViewModel.kt new file mode 100644 index 0000000..5b1d21e --- /dev/null +++ b/app/src/main/java/com/bbit/silk/base/BaseViewModel.kt @@ -0,0 +1,37 @@ + +import androidx.lifecycle.ViewModel +import com.bbit.silk.ui.view.LoadingDialogData +import com.bbit.silk.ui.view.TipsDialogData +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update + +open class BaseViewModel : ViewModel() { + + private val _tipDialogState = MutableStateFlow(TipsDialogData()) + val tipsDialog: StateFlow = _tipDialogState.asStateFlow() + private val _loadingDialogState = MutableStateFlow(LoadingDialogData()) + val loadingDialog: StateFlow = _loadingDialogState.asStateFlow() + + fun hideTipsDialog() { + _tipDialogState.update { it.copy(showDialog = false) } + } + + fun showTipsDialog(content: String) { + _tipDialogState.update { it.copy(showDialog = true, content = content) } + } + + fun hideLoadingDialog() { + _loadingDialogState.update { it.copy(showDialog = false) } + } + + fun showProcessDialog(process: Int, content: String) { + _loadingDialogState.update { it.copy(showDialog = true,showProcess = true, process = process, content = content) } + } + + fun showLoadingDialog(content: String) { + _loadingDialogState.update { it.copy(showDialog = true, content = content) } + } + +} diff --git a/app/src/main/java/com/bbit/silk/base/CustomMaterialComponents.kt b/app/src/main/java/com/bbit/silk/base/CustomMaterialComponents.kt new file mode 100644 index 0000000..ccc985e --- /dev/null +++ b/app/src/main/java/com/bbit/silk/base/CustomMaterialComponents.kt @@ -0,0 +1,160 @@ +package com.bbit.silk.base + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.LocalTextStyle +import androidx.compose.material.MaterialTheme +import androidx.compose.material.MaterialTheme.colors +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.bbit.myapplication.ui.theme.MyColors +import com.lt.compose_views.text_field.BackgroundComposeWithTextField +import com.lt.compose_views.text_field.GoodTextField +import com.lt.compose_views.text_field.HintComposeWithTextField + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年05月13日 10:09:12 + */ + +@Composable +fun MyButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + shape: Shape = ButtonDefaults.shape, + border: BorderStroke? = null, + contentPadding: PaddingValues = ButtonDefaults.ContentPadding, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + content: @Composable RowScope.() -> Unit +) { + Button( + onClick = onClick, + modifier = modifier, + enabled = enabled, + interactionSource = interactionSource, + shape = shape, + border = border, + colors = ButtonDefaults.buttonColors(containerColor = MyColors.Green), + contentPadding = contentPadding, + content = content + ) +} + +@Composable +fun MyCard( + modifier: Modifier = Modifier, + shape: Shape = CardDefaults.shape, + border: BorderStroke? = null, + content: @Composable ColumnScope.() -> Unit +) { + Card( + modifier = modifier, + shape = shape, + colors = CardDefaults.cardColors(containerColor = if (isSystemInDarkTheme()) Color.Gray else Color.White), + elevation = CardDefaults.cardElevation(defaultElevation = 6.dp), + border = border, + content = content + ) +} + +@Composable +fun MyGreenCard( + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit +) { + Card( + colors = CardDefaults.cardColors( + containerColor = if (isSystemInDarkTheme()) Color.DarkGray else Color(0xFFF0FCF5) + ), + modifier = modifier + ){ + content() + } +} + +@Preview(showBackground = true) +@Composable +fun MyTextFieldPreview() { + MyTextField( + value = "Hello", + onValueChange = {}) +} + +@Composable +fun MyTextField( + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + hint: String? = null, + maxLines: Int = 1, + fontSize: TextUnit = 16.sp, + fontColor: Color = Color(0xff333333), + maxLength: Int = Int.MAX_VALUE, + contentAlignment: Alignment.Vertical = Alignment.CenterVertically, + leading: (@Composable RowScope.() -> Unit)? = null, + trailing: (@Composable RowScope.() -> Unit)? = null, + background: BackgroundComposeWithTextField? = BackgroundComposeWithTextField.DEFAULT, + horizontalPadding: Dp = 15.dp, + enabled: Boolean = true, + readOnly: Boolean = false, + textStyle: TextStyle = LocalTextStyle.current, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + visualTransformation: VisualTransformation = VisualTransformation.None, + onTextLayout: (TextLayoutResult) -> Unit = {}, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + cursorBrush: Brush = SolidColor(MaterialTheme.colors.primary), +) { + GoodTextField( + value = value, + onValueChange = onValueChange, + modifier = modifier.height(45.dp), + hint = hint?.let { HintComposeWithTextField.createTextHintCompose(it) }, + maxLines = maxLines, + fontSize = fontSize, + fontColor = fontColor, + maxLength = maxLength, + contentAlignment = contentAlignment, + leading = leading, + trailing = trailing, + background = background, + horizontalPadding = horizontalPadding, + enabled = enabled, + readOnly = readOnly, + textStyle = textStyle, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + visualTransformation = visualTransformation, + onTextLayout = onTextLayout, + interactionSource = interactionSource, + cursorBrush = SolidColor(Color.Black) + ) +} diff --git a/app/src/main/java/com/bbit/silk/base/QueryComposeable.kt b/app/src/main/java/com/bbit/silk/base/QueryComposeable.kt new file mode 100644 index 0000000..55c888d --- /dev/null +++ b/app/src/main/java/com/bbit/silk/base/QueryComposeable.kt @@ -0,0 +1,357 @@ +package com.bbit.silk.base + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.Divider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import com.bbit.silk.R +import com.bbit.silk.model.QueryList +import com.bbit.silk.ui.view.ConfirmDialog +import com.bbit.silk.viewmodel.DataViewModel +import com.bigkoo.pickerview.builder.TimePickerBuilder +import com.blankj.utilcode.util.TimeUtils +import java.util.Calendar + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年05月10日 10:23:52 + */ + + +@Preview(showBackground = true) +@Composable +fun BaseQueryByDatePreView() { + BaseQueryByDate("2024-05-06", "2024-05-06") { _, _, _ -> } +} + +@Composable +fun BaseQueryByDate( + startDate: String, + endDate: String, + showKeyQuery: Boolean = true,//是否使用关键字查询 + onContentChange: (startDate: String, endDate: String, key: String) -> Unit +) { + val context = LocalContext.current + var startDate by rememberSaveable { mutableStateOf(startDate) } + var endDate by rememberSaveable { mutableStateOf(endDate) } + var key by rememberSaveable { mutableStateOf("") } + Column { + Row( + modifier = Modifier + .fillMaxWidth() + .height(60.dp) + .padding(horizontal = 15.dp) + .heightIn(min = 40.dp) + ) { + Image( + painter = painterResource(id = R.drawable.date), + contentDescription = null, + Modifier + .size(40.dp) + .padding(start = 5.dp) + .align(Alignment.CenterVertically) + ) + Text( + text = startDate, + textAlign = TextAlign.Center, + modifier = Modifier + .weight(1f) + .align(Alignment.CenterVertically) + .noVisualFeedbackClickable { + val defaultDate = Calendar.getInstance() + defaultDate.time = TimeUtils.string2Date(startDate, "yyyy-MM-dd") + TimePickerBuilder(context) label@{ date, v1 -> + startDate = TimeUtils.date2String(date, "yyyy-MM-dd") + onContentChange(startDate, endDate, key) + } + .setDate(defaultDate) + .build() + .show() + } + ) + Image( + painter = painterResource(id = R.drawable.next_long), + contentDescription = null, + Modifier + .size(30.dp) + .align(Alignment.CenterVertically) + ) + Text( + text = endDate, + textAlign = TextAlign.Center, + modifier = Modifier + .padding() + .weight(1f) + .align(Alignment.CenterVertically) + .noVisualFeedbackClickable { + val defaultDate = Calendar.getInstance() + defaultDate.time = TimeUtils.string2Date(endDate, "yyyy-MM-dd") + TimePickerBuilder(context) label@{ date, v1 -> + endDate = TimeUtils.date2String(date, "yyyy-MM-dd") + onContentChange(startDate, endDate, key) + } + .setDate(defaultDate) + .build() + .show() + } + ) + } + Divider() + if (showKeyQuery) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 15.dp) + .heightIn(min = 40.dp) + ) { + Image( + painter = painterResource(id = R.drawable.search), + contentDescription = null, + Modifier + .size(40.dp) + .padding(horizontal = 5.dp) + .align(Alignment.CenterVertically) + ) + MyTextField( + value = key, onValueChange = { key = it }, + hint = "请输入关键字", + modifier = Modifier + .weight(1f) + .padding(horizontal = 15.dp, vertical = 5.dp) + .align(Alignment.CenterVertically) + ) + MyButton( + onClick = { onContentChange(startDate, endDate, key) }, + modifier = Modifier + .align(Alignment.CenterVertically) + ) { + Text(text = "查询") + } + } + Divider() + } + } +} + +@Preview(showBackground = true, widthDp = 400) +@Composable +fun ItemDataPreview() { + ItemData(name = "杨建国", id = "99202108090003", state = "待定价", listOf()) +} + +@Composable +fun ItemData( + name: String, id: String, state: String, + data: List, + showCancel: Boolean = false, + showConfirm: Boolean = false, + czsysid: String = "", + navController: NavController? = null, + presenter: DataViewModel = viewModel(), + onClick: (() -> Unit)? = null +) { + var type by remember { mutableStateOf(0) } + var showConfirmDialog by remember { mutableStateOf(false) } + ConfirmDialog( + title = "提示", + content = "确定要" + (if (type == -1) "弃售" else "确定售") + id + "吗", + showDialog = showConfirmDialog, + onSuccess = { + presenter.cancelOrConfirm(navController, id = czsysid, type) + showConfirmDialog = false + }, + onDismiss = { showConfirmDialog = false }) + MyCard( + modifier = Modifier + .padding(15.dp, 5.dp, 15.dp, 10.dp) + .then( + if (onClick != null) { + Modifier.clickable { onClick() } + } else { + Modifier + } + ) + ) { + Column { + Box(modifier = Modifier.fillMaxWidth()) { + Row(modifier = Modifier.padding(15.dp)) { + Text(text = name, fontWeight = FontWeight.Bold) + Text(text = id, Modifier.padding(start = 10.dp), fontWeight = FontWeight.Bold) + } + Card( + shape = RoundedCornerShape(0.dp, 0.dp, 0.dp, 10.dp), + modifier = Modifier + .align(Alignment.TopEnd) + ) { + Text( + modifier = Modifier.padding(horizontal = 10.dp, vertical = 5.dp), + text = state + ) + } + } + Column { + ListHeader(listOf("茧别", "包数", "毛重(公斤)", "单价(元)")) + } + data.forEach { + DynamicValuesRow(listOf(it.sgTypeName, it.baoshu, it.maozhong, it.price)) + } + if (showCancel || showConfirm) { + Divider() + } + Row { + if (showCancel) { + Text( + text = "弃售", + color = Color.LightGray, + modifier = Modifier + .weight(1f) + .padding(vertical = 5.dp) + .clickable { + type = -1 + showConfirmDialog = true + }, + textAlign = TextAlign.Center + ) + } + if (showConfirm) { + Box( + modifier = Modifier + .background(Color.Gray) + .size(1.dp, 20.dp) + .align(Alignment.CenterVertically) + ) + Text( + text = "确认售", + modifier = Modifier + .weight(1f) + .clickable { + type = 2 + showConfirmDialog = true + } + .padding(vertical = 5.dp), + textAlign = TextAlign.Center + ) + + } + } + } + + } +} + +@Composable +fun ListHeader(titles: List) { + Row( + modifier = Modifier + .background( + Brush.verticalGradient( + colors = listOf( + Color(0xFFE8FFF4), // 绿色 + Color(0xFFFFFFFF), // 白色 + ) + ) + ) + ) { + titles.forEach { title -> + Text( + text = title, + modifier = Modifier + .weight(1f) + .padding(vertical = 10.dp), + textAlign = TextAlign.Center + ) + } + } +} + +@Composable +fun DynamicValuesRow(values: List, onClick: (() -> Unit)? = null) { + Row( + modifier = Modifier + .then( + if (onClick != null) { + Modifier.clickable { onClick() } + } else { + Modifier + } + ) + ) { + // 遍历值列表,并为每个值创建一个 Text 组件 + values.forEach { value -> + Text( + text = value.toString(), + modifier = Modifier + .weight(1f) + .padding(vertical = 5.dp), + textAlign = TextAlign.Center + ) + } + } +} + +/** + * 列表暂无数据 + */ +@Composable +fun NoData() { + Box( + modifier = Modifier + .fillMaxWidth() + ) { + Column( + modifier = Modifier + .wrapContentWidth() + .padding(20.dp) + .align(Alignment.Center) + ) { + Image( + painter = painterResource(id = R.drawable.tips), + contentDescription = "Tips", + modifier = Modifier + .padding(vertical = 10.dp) + .wrapContentWidth() + .align(Alignment.CenterHorizontally) + ) + Text( + text = "暂无数据", + textAlign = TextAlign.Center, + modifier = Modifier + .padding(vertical = 20.dp) + .widthIn(200.dp) + ) + } + } +} diff --git a/app/src/main/java/com/bbit/silk/base/VerticalGrid.kt b/app/src/main/java/com/bbit/silk/base/VerticalGrid.kt new file mode 100644 index 0000000..1996697 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/base/VerticalGrid.kt @@ -0,0 +1,56 @@ +package com.bbit.silk.base + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.Layout + + +/** + * Taken from Jetsnack sample. Right now there is no inbuilt grid but we can make + * Custom layout like below which takes number of items and place them in Grid fashion. + + * A simple grid which lays elements out vertically in evenly sized [columns]. + */ +@Composable +fun VerticalGrid( + modifier: Modifier = Modifier, + columns: Int = 2, + content: @Composable () -> Unit +) { + Layout( + content = content, + modifier = modifier + ) { measurables, constraints -> + val itemWidth = constraints.maxWidth / columns + // Keep given height constraints, but set an exact width + val itemConstraints = constraints.copy( + minWidth = itemWidth, + maxWidth = itemWidth + ) + // Measure each item with these constraints + val placeables = measurables.map { it.measure(itemConstraints) } + // Track each columns height so we can calculate the overall height + val columnHeights = Array(columns) { 0 } + placeables.forEachIndexed { index, placeable -> + val column = index % columns + columnHeights[column] += placeable.height + } + val height = (columnHeights.maxOrNull() ?: constraints.minHeight) + .coerceAtMost(constraints.maxHeight) + layout( + width = constraints.maxWidth, + height = height + ) { + // Track the Y co-ord per column we have placed up to + val columnY = Array(columns) { 0 } + placeables.forEachIndexed { index, placeable -> + val column = index % columns + placeable.placeRelative( + x = column * itemWidth, + y = columnY[column] + ) + columnY[column] += placeable.height + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/About.kt b/app/src/main/java/com/bbit/silk/model/About.kt new file mode 100644 index 0000000..d1a8bea --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/About.kt @@ -0,0 +1,29 @@ +package com.bbit.silk.model + + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年05月08日 11:57:28 + */ +data class About( + val `data`: Data = Data(), + val msg: String = "", + val result: Boolean = false +) { + data class Data( + val about: String = "", + val items: List = listOf() + ) { + data class Item( + val items: List = listOf(), + val name: String = "" + ) { + data class Item( + val name: String = "", + val value: String = "" + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/AllType.kt b/app/src/main/java/com/bbit/silk/model/AllType.kt new file mode 100644 index 0000000..5acb5ed --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/AllType.kt @@ -0,0 +1,28 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月03日 15:18:09 + */ +data class AllType( + @SerializedName("data") + val `data`: List = listOf(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("group") + val group: String = "", + @SerializedName("name") + val name: String = "", + @SerializedName("sort") + val sort: Int = 0, + @SerializedName("sysid") + val sysid: String = "" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/Auth.kt b/app/src/main/java/com/bbit/silk/model/Auth.kt new file mode 100644 index 0000000..8a8b9b9 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/Auth.kt @@ -0,0 +1,38 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月08日 18:05:16 + */ +data class Auth( + @SerializedName("data") + val `data`: Data = Data(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("Applicant") + val applicant: String = "", + @SerializedName("ClientType") + val clientType: String = "", + @SerializedName("Flag") + val flag: Int = 0, + @SerializedName("HardwareId") + val hardwareId: String = "", + @SerializedName("Job") + val job: String = "", + @SerializedName("Memo") + val memo: String = "", + @SerializedName("Phone") + val phone: String = "", + @SerializedName("Sysid") + val sysid: String = "", + @SerializedName("TenantCode") + val tenantCode: String = "" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/CheckAuth.kt b/app/src/main/java/com/bbit/silk/model/CheckAuth.kt new file mode 100644 index 0000000..9098e77 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/CheckAuth.kt @@ -0,0 +1,38 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月09日 09:02:52 + */ +data class CheckAuth( + @SerializedName("data") + val `data`: Data = Data(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("Applicant") + val applicant: String = "", + @SerializedName("ClientType") + val clientType: String = "", + @SerializedName("Flag") + val flag: Int = 0, + @SerializedName("HardwareId") + val hardwareId: String = "", + @SerializedName("Job") + val job: String = "", + @SerializedName("Memo") + val memo: String = "", + @SerializedName("Phone") + val phone: String = "", + @SerializedName("Sysid") + val sysid: String = "", + @SerializedName("TenantCode") + val tenantCode: String = "" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/CommonResponse.kt b/app/src/main/java/com/bbit/silk/model/CommonResponse.kt new file mode 100644 index 0000000..6a87a5c --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/CommonResponse.kt @@ -0,0 +1,16 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * 通用网络请求 + * Data值为唯一值的 + */ +data class CommonResponse( + @SerializedName("data") + val `data`: Any = Any(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/Login.kt b/app/src/main/java/com/bbit/silk/model/Login.kt new file mode 100644 index 0000000..629b70e --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/Login.kt @@ -0,0 +1,34 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description 登录获取Token + * @Author DuanKaiji + * @CreateTime 2024年03月27日 13:59 + */ +data class Login( + @SerializedName("data") + val `data`: Data = Data(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("AccessToken") + val accessToken: String = "", + @SerializedName("ExpireTime") + val expireTime: String = "", + @SerializedName("ExpiresIn") + val expiresIn: Int = 0, + @SerializedName("RefreshToken") + val refreshToken: String = "", + @SerializedName("TokenType") + val tokenType: String = "", + @SerializedName("UserId") + val userId: String = "", + @SerializedName("UserName") + val userName: String = "" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/QueryList.kt b/app/src/main/java/com/bbit/silk/model/QueryList.kt new file mode 100644 index 0000000..75a9073 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/QueryList.kt @@ -0,0 +1,73 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月03日 08:59:59 + */ +data class QueryList( + @SerializedName("data") + val `data`: List = listOf(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("pageinfo") + val pageinfo: Pageinfo = Pageinfo(), + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("CzCode") + val czCode: String = "", + @SerializedName("CzSysid") + val czSysid: String = "", + @SerializedName("Items") + val items: List = listOf(), + @SerializedName("NhName") + val nhName: String = "", + @SerializedName("Status") + val status: String = "", + @SerializedName("StatusCode") + val statusCode: Int = 0 + ) { + data class Item( + /** + * 是否允许编辑价格 0 不允许 + */ + @SerializedName("AllowEditPrice") + val allowEditPrice: Int = 0, + @SerializedName("Baoshu") + val baoshu: Int = 0, + @SerializedName("Jine") + val jine: Double = 0.0, + @SerializedName("Jingzhong") + val jingzhong: Double = 0.0, + @SerializedName("Kouzhong") + val kouzhong: Int = 0, + @SerializedName("Maozhong") + val maozhong: Double = 0.0, + @SerializedName("Pizhong") + val pizhong: Double = 0.0, + @SerializedName("Price") + val price: Double = 0.0, + @SerializedName("SgTypeName") + val sgTypeName: String = "", + @SerializedName("SgTypeSysid") + val sgTypeSysid: String = "" + ) + } + + data class Pageinfo( + @SerializedName("Count") + val count: Int = 0, + @SerializedName("Limit") + val limit: Int = 0, + @SerializedName("Page") + val page: Int = 0, + @SerializedName("PageCount") + val pageCount: Int = 0, + @SerializedName("Paged") + val paged: Boolean = false + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/Statistics.kt b/app/src/main/java/com/bbit/silk/model/Statistics.kt new file mode 100644 index 0000000..b0e4ad7 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/Statistics.kt @@ -0,0 +1,53 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月03日 15:58:17 + */ +data class Statistics( + @SerializedName("data") + val `data`: Data = Data(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("items") + val items: List = listOf(), + @SerializedName("price") + val price: Double = 0.0, + @SerializedName("sumjingzhong") + val sumjingzhong: Double = 0.0, + @SerializedName("sumkouzhong") + val sumkouzhong: Int = 0, + @SerializedName("summaozhong") + val summaozhong: Double = 0.0, + @SerializedName("summoney") + val summoney: Int = 0, + @SerializedName("sumpizhong") + val sumpizhong: Double = 0.0 + ) { + data class Item( + @SerializedName("jingzhong") + val jingzhong: Double = 0.0, + @SerializedName("kouzhong") + val kouzhong: Int = 0, + @SerializedName("maozhong") + val maozhong: Double = 0.0, + @SerializedName("money") + val money: Double = 0.0, + @SerializedName("pizhong") + val pizhong: Double = 0.0, + @SerializedName("price") + val price: Double = 0.0, + @SerializedName("sgtypename") + val sgtypename: String = "", + @SerializedName("sgtypesysid") + val sgtypesysid: String = "" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/ToConvert.kt b/app/src/main/java/com/bbit/silk/model/ToConvert.kt new file mode 100644 index 0000000..ec0435c --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/ToConvert.kt @@ -0,0 +1,22 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description 茧别转换 + * @Author DuanKaiji + * @CreateTime 2024年04月03日 15:12:51 + */ +data class ToConvert( + @SerializedName("czsysid") + var czsysid: String = "", + @SerializedName("items") + var items: List = listOf() +) { + data class Item( + @SerializedName("newsgtypesysid") + var newsgtypesysid: String = "", + @SerializedName("oldsgtypesysid") + var oldsgtypesysid: String = "" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/ToTareSubmit.kt b/app/src/main/java/com/bbit/silk/model/ToTareSubmit.kt new file mode 100644 index 0000000..a8a53ff --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/ToTareSubmit.kt @@ -0,0 +1,47 @@ +package com.bbit.silk.model + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月03日 17:36:22 + */ +@Parcelize +data class ToTareSubmit( + @SerializedName("czsysid") + val czsysid: String = "", + @SerializedName("items") + var items: List = listOf() +) : Parcelable { + @Parcelize + data class Item( + @SerializedName("kouzhong") + var kouzhong: Double = 0.0, + @SerializedName("pizhong") + var pizhong: Double = 0.0, + @SerializedName("price") + var price: Double = 0.0, + @SerializedName("sgtypesysid") + val sgtypesysid: String = "" + ) : Parcelable { + /** + * 重写 equals 方法 使用 sgtypesysid 判断是否相等 + */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Item) return false + return sgtypesysid == other.sgtypesysid + } + + /** + * 重写 hashCode 方法 使用 sgtypesysid 的 hashCode + */ + override fun hashCode(): Int { + return sgtypesysid.hashCode() + } + } + +} diff --git a/app/src/main/java/com/bbit/silk/model/TodayPrice.kt b/app/src/main/java/com/bbit/silk/model/TodayPrice.kt new file mode 100644 index 0000000..5a758f4 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/TodayPrice.kt @@ -0,0 +1,33 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月01日 11:00:56 + */ +data class TodayPrice( + @SerializedName("data") + val `data`: Data = Data(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("Items") + val items: List = listOf(), + @SerializedName("RefreshTime") + val refreshTime: String = "" + ) { + data class Item( + @SerializedName("maxprice") + val maxprice: String = "", + @SerializedName("minprice") + val minprice: String = "", + @SerializedName("name") + val name: String = "" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/Update.kt b/app/src/main/java/com/bbit/silk/model/Update.kt new file mode 100644 index 0000000..43463b7 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/Update.kt @@ -0,0 +1,28 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月02日 16:16:42 + */ +data class Update( + @SerializedName("data") + val `data`: Data = Data(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("Url") + val url: String = "", + @SerializedName("VersionDescription") + val versionDescription: String = "", + @SerializedName("VersionName") + val versionName: String = "", + @SerializedName("VersionNumber") + val versionNumber: Int = 0 + ) +} diff --git a/app/src/main/java/com/bbit/silk/model/UserInfo.kt b/app/src/main/java/com/bbit/silk/model/UserInfo.kt new file mode 100644 index 0000000..8b2ec11 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/UserInfo.kt @@ -0,0 +1,38 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月02日 10:19:20 + */ +data class UserInfo( + @SerializedName("data") + val `data`: Data = Data(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("DepName") + val depName: String = "", + @SerializedName("DepSysid") + val depSysid: String = "", + @SerializedName("LoginAccount") + val loginAccount: String = "", + @SerializedName("RoleName") + val roleName: String = "", + @SerializedName("TenantCode") + val tenantCode: String = "", + @SerializedName("TenantID") + val tenantID: Long = 0, + @SerializedName("TenantName") + val tenantName: String = "", + @SerializedName("UserName") + val userName: String = "", + @SerializedName("UserSysID") + val userSysID: String = "" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/model/Weather.kt b/app/src/main/java/com/bbit/silk/model/Weather.kt new file mode 100644 index 0000000..1486f48 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/model/Weather.kt @@ -0,0 +1,53 @@ +package com.bbit.silk.model + +import com.google.gson.annotations.SerializedName + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月07日 11:24:17 + */ +data class Weather( + @SerializedName("data") + val `data`: Data = Data(), + @SerializedName("msg") + val msg: String = "", + @SerializedName("result") + val result: Boolean = false +) { + data class Data( + @SerializedName("adcode") + val adcode: String = "", + @SerializedName("casts") + val casts: List = listOf(), + @SerializedName("city") + val city: String = "加载中", + @SerializedName("province") + val province: String = "", + @SerializedName("reporttime") + val reporttime: String = "" + ) { + data class Cast( + @SerializedName("date") + val date: String = "", + @SerializedName("daypower") + val daypower: String = "", + @SerializedName("daytemp") + val daytemp: String = "", + @SerializedName("dayweather") + val dayweather: String = "", + @SerializedName("daywind") + val daywind: String = "", + @SerializedName("nightpower") + val nightpower: String = "", + @SerializedName("nighttemp") + val nighttemp: String = "", + @SerializedName("nightweather") + val nightweather: String = "", + @SerializedName("nightwind") + val nightwind: String = "", + @SerializedName("week") + val week: String = "" + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/activity/MainActivity.kt b/app/src/main/java/com/bbit/silk/ui/activity/MainActivity.kt new file mode 100644 index 0000000..da4f949 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/activity/MainActivity.kt @@ -0,0 +1,101 @@ +package com.bbit.silk.ui.activity + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Surface +import androidx.compose.ui.Modifier +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.bbit.myapplication.ui.theme.AppTheme +import com.bbit.silk.model.QueryList +import com.bbit.silk.ui.screen.MainScreen +import com.bbit.silk.ui.screen.core.ToConfirmSaleScreenScreen +import com.bbit.silk.ui.screen.core.ToConvertScreen +import com.bbit.silk.ui.screen.core.ToTareScreen +import com.bbit.silk.ui.screen.core.TotalScreen +import com.bbit.silk.ui.screen.core.UserScreen +import com.bbit.silk.ui.screen.coreFunc.ConvertScreen +import com.bbit.silk.ui.screen.coreFunc.TareScreen +import com.bbit.silk.ui.screen.login.AboutScreen +import com.bbit.silk.ui.screen.login.AuthScreen +import com.bbit.silk.ui.screen.login.LoginScreen +import com.bbit.silk.ui.screen.login.UpdateScreen +import com.bbit.silk.utils.MyUtil +import com.bbit.silk.utils.global.Global +import com.blankj.utilcode.util.GsonUtils +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.core.view.WindowCompat +import com.bbit.silk.utils.log.MyLog + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月30日 10:29:21 + */ +open class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + installSplashScreen() + super.onCreate(savedInstanceState) + WindowCompat.setDecorFitsSystemWindows(window, false) + MyLog.test("HostId" + Global.getDeviceId()) + setContent { + AppTheme { + Surface( + modifier = Modifier.fillMaxSize() + ) { + // 创建导航控制器 + val navController = rememberNavController() + // 设置NavHost + NavHost( + navController = navController, + startDestination = "main" // 设置起始页面 + ) { + composable("login") { + AppTheme { + LoginScreen( + usernameDefault = Global.getUserAccount(),//test:15398380348 + versionName = MyUtil.getVersionName(), + companyIdVal = Global.getCompanyId(), + modifier = Modifier.fillMaxSize(), + navController = navController + ) + } + } + composable("main") { MainScreen(navController = navController) } + composable("about") { AboutScreen(navController = navController) } + composable("auth") { AuthScreen(navController = navController) } + composable("update") { UpdateScreen(navController = navController) } + composable("main/user") { UserScreen(navController = navController) } + composable("main/total") { TotalScreen(navController = navController) } + composable("main/toConfirmSale") { ToConfirmSaleScreenScreen(navController = navController) } + + composable("main/toConvert") { ToConvertScreen(navController = navController) } + composable("main/toConvert/convert/{data}") { + ConvertScreen( + GsonUtils.fromJson( + it.arguments?.getString("data"), + QueryList.Data::class.java + ), navController = navController + ) + } + + composable("main/toTare") { ToTareScreen(navController = navController) } + composable("main/toTare/tare/{data}") { + TareScreen( + GsonUtils.fromJson( + it.arguments?.getString("data"), + QueryList.Data::class.java + ), navController = navController + ) + } + } + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/MainScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/MainScreen.kt new file mode 100644 index 0000000..53a0992 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/MainScreen.kt @@ -0,0 +1,381 @@ +package com.bbit.silk.ui.screen; + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.paddingFromBaseline +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.R +import com.bbit.silk.base.ContentFrame +import com.bbit.silk.base.MyCard +import com.bbit.silk.base.MyGreenCard +import com.bbit.silk.base.VerticalGrid +import com.bbit.silk.base.noVisualFeedbackClickable +import com.bbit.silk.model.TodayPrice +import com.bbit.silk.model.Weather +import com.bbit.silk.ui.view.ConfirmDialog +import com.bbit.silk.ui.view.LoadingDialog +import com.bbit.silk.utils.MyUtil +import com.bbit.silk.viewmodel.MainViewModel +import com.bbit.silk.viewmodel.UpdateViewModel +import com.blankj.utilcode.util.AppUtils +import com.blankj.utilcode.util.TimeUtils +import java.text.SimpleDateFormat + +@Preview(showBackground = true, widthDp = 400, showSystemUi = true) +@Composable +fun MainPreview() { + MainScreen(navController = rememberNavController()) +} + +@Composable +fun MainScreen( + mainPresenter: MainViewModel = viewModel(), + updatePresenter: UpdateViewModel = viewModel(), + navController: NavController +) { + var showExitDialog by rememberSaveable { mutableStateOf(false) } + val showUpdateDialog = remember { mutableStateOf(false) } + val versionDescription = remember { mutableStateOf("") } + val priceInfo = mainPresenter.price.collectAsState().value + val versionInfo = updatePresenter.updateInfo.collectAsState().value + if (versionInfo.versionNumber > MyUtil.getVersionId()) { + //强制升级 + showUpdateDialog.value = true + versionDescription.value = versionInfo.versionDescription + } else { + mainPresenter.refreshInfo() + } + BackHandler { showExitDialog = true } + ConfirmDialog( + title = "提示", + content = "是否关闭程序?", + showDialog = showExitDialog, + onSuccess = { AppUtils.exitApp() }, + onDismiss = { showExitDialog = false }) + ConfirmDialog( + title = "检测到新版本", + content = "更新内容:\n${versionDescription.value}", + canManualClose = false, + showDialog = showUpdateDialog.value, + onSuccess = { + //下载更新 + showUpdateDialog.value = false + updatePresenter.downFile() + } + ) + if (mainPresenter.getInLoginScreen.collectAsState().value) { + navController.navigate("login") { + popUpTo(navController.graph.startDestinationId) { inclusive = true } + launchSingleTop = true + } + } + // 展示更新进度的弹窗 + LoadingDialog(updatePresenter.loadingDialog.collectAsState().value) + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()) + ) { + Box(modifier = Modifier.fillMaxWidth()) { + Image( + modifier = Modifier + .padding() + .fillMaxWidth(), + painter = painterResource(R.drawable.bg_main), + contentDescription = null, + contentScale = ContentScale.Crop + ) + Image( + painter = painterResource(id = R.drawable.menu), contentDescription = null, + modifier = Modifier + .align(Alignment.TopEnd) + .size(90.dp) + .padding(30.dp) + .clickable{ navController.navigate("main/user") } + ) + Column( + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = "智慧收茧", + color = Color.White, + fontWeight = FontWeight.Bold, + modifier = Modifier + .padding(vertical = 30.dp) + .fillMaxWidth(), + textAlign = TextAlign.Center, + fontSize = 20.sp + ) + MyCard( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + Row(modifier = Modifier.fillMaxWidth()) { + Image( + painter = painterResource(id = R.drawable.logo), + modifier = Modifier + .size(70.dp) + .padding(10.dp), + contentDescription = null + ) + Column(modifier = Modifier.padding(vertical = 15.dp)) { + Row { + Text(text = "所属茧站:", color = Color.Green) + Text(text = mainPresenter.userInfo.collectAsState().value.depName) + } + Row { + Text(text = "登录用户:", color = Color.Green) + Text(text = mainPresenter.userInfo.collectAsState().value.userName) + MyGreenCard { + Text( + modifier = Modifier.padding(horizontal = 10.dp), + text = mainPresenter.userInfo.collectAsState().value.roleName + ) + } + } + } + } + } + } + } + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 15.dp, vertical = 10.dp) + ) { + Row { + mainFunction(Modifier.weight(1f), id = R.drawable.price, name = "扣皮定价") { + navController.navigate("main/toTare") + } + mainFunction(Modifier.weight(1f), id = R.drawable.query, name = "待确认售") { + navController.navigate("main/toConfirmSale") + } + } + Row { + mainFunction(Modifier.weight(1f), id = R.drawable.kinds, name = "茧别转换") { + navController.navigate("main/toConvert") + } + mainFunction(Modifier.weight(1f), id = R.drawable.total, name = "收购统计") { + navController.navigate("main/total") + } + } + // 价格信息 + price(mainPresenter = mainPresenter, priceInfo = priceInfo) + // 天气信息 + weather(mainPresenter.weather.collectAsState().value) + } + } +} + +@Composable +fun price( + mainPresenter: MainViewModel, + priceInfo: TodayPrice.Data +) { + ContentFrame(title = "今日价格(元/公斤)", buttonTitle = "刷新", buttonClick = { + mainPresenter.refreshPriceOfToday() + }) { + Column { + VerticalGrid(columns = 2) { + priceInfo.items.forEach { + PriceInfoItem(it) + } + } + Row( + modifier = Modifier + .padding(top = 10.dp) + .fillMaxWidth() + ) { + Spacer(modifier = Modifier.weight(1f)) + MyGreenCard { + Text( + modifier = Modifier + .padding(5.dp), + text = "发布时间:${priceInfo.refreshTime}" + ) + } + } + } + + } +} + +/** + * 价格信息 + */ +@Composable +fun PriceInfoItem(it: TodayPrice.Data.Item) { + MyGreenCard( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 5.dp) + .padding(end = 5.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(5.dp), + ) { + Text( + text = it.name, + fontSize = 14.sp, + modifier = Modifier.wrapContentWidth() + ) + Text( + text = "${it.minprice} ~ ${it.maxprice}", + fontSize = 14.sp, + textAlign = TextAlign.End, + modifier = Modifier.weight(1f) + ) + } + } +} + +/** + * 主菜单四个主要功能模块 + */ +@Composable +fun mainFunction( + modifier: Modifier, + id: Int, + name: String, + onClick: () -> Unit +) { + Box( + modifier = modifier + .fillMaxWidth() + .padding(5.dp) + .clickable { onClick() } + ) { + Image( + modifier = Modifier + .fillMaxWidth(), + painter = painterResource(id = id), contentDescription = null, + contentScale = ContentScale.Crop + ) + Text( + modifier = Modifier + .fillMaxWidth() + .paddingFromBaseline(100.dp), + textAlign = TextAlign.Center, + color = Color.White, + text = name + ) + } + +} + +@Composable +fun weather(weather: Weather.Data) { + ContentFrame(title = "天气预报(${weather.city})") { + Row { + if (weather.casts.size < 3) { + return@Row + } + weatherDetail( + Modifier.weight(1f), + date1 = "今天", + date2 = weather.casts[0].date, + content = MyUtil.formatTemperatureAndWeather(weather.casts[0]) + ) + //分割线 + Box( + Modifier + .width(1.dp) + .height(70.dp) + .background(Color.LightGray) + ) + weatherDetail( + Modifier.weight(1f), + date1 = "明天", + date2 = weather.casts[1].date, + content = MyUtil.formatTemperatureAndWeather(weather.casts[1]) + ) + Box( + Modifier + .width(1.dp) + .height(70.dp) + .background(if (isSystemInDarkTheme()) Color.LightGray else Color.LightGray) + ) + weatherDetail( + Modifier.weight(1f), + date1 = TimeUtils.getChineseWeek( + weather.casts[2].date, + SimpleDateFormat("yyyy-MM-dd") + ), + date2 = weather.casts[2].date, + content = MyUtil.formatTemperatureAndWeather(weather.casts[2]) + ) + } + + } +} + +@Composable +fun weatherDetail(modifier: Modifier, date1: String, date2: String, content: String) { + Column( + modifier = modifier + .fillMaxWidth() + ) { + Text( + modifier = Modifier.fillMaxWidth(), + fontSize = 15.sp, + textAlign = TextAlign.Center, + text = date1 + ) + Text( + modifier = Modifier + .fillMaxWidth() + .padding(top = 5.dp), + fontSize = 14.sp, + color = if (isSystemInDarkTheme()) Color.LightGray else Color.Gray, + textAlign = TextAlign.Center, + text = date2 + ) + Text( + modifier = Modifier + .fillMaxWidth() + .padding(top = 5.dp), + fontSize = 14.sp, + textAlign = TextAlign.Center, + text = content + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/core/ToConfirmSaleScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/core/ToConfirmSaleScreen.kt new file mode 100644 index 0000000..b8fc18b --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/core/ToConfirmSaleScreen.kt @@ -0,0 +1,56 @@ +package com.bbit.silk.ui.screen.core + +import android.annotation.SuppressLint +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.base.BaseFixedTabRow +import com.bbit.silk.base.BaseQueryScreen +import com.bbit.silk.base.MainFrame +import com.bbit.silk.viewmodel.DataViewModel + +/** + * + * @Description 待确认售 + * @Author DuanKaiji + * @CreateTime 2024年04月30日 10:11:17 + */ +@Preview(showBackground = true, widthDp = 400) +@Composable +fun ToConfirmSaleScreenPreview() { + ToConfirmSaleScreenScreen(navController = rememberNavController()) +} + +@SuppressLint("UnrememberedMutableState") +@Composable +fun ToConfirmSaleScreenScreen( + presenter: DataViewModel = viewModel(), + navController: NavController +) { + val presenter1 = DataViewModel() + val presenter2 = DataViewModel() + MainFrame(title = "待确认售", presenter = presenter, navController = navController) { + BaseFixedTabRow(tabData = listOf( + Pair("待确认售") { + Box(modifier = Modifier.fillMaxSize()) { + BaseQueryScreen(queryType = 2, showConfirm = true, showCancel = true, presenter = presenter1) + } + }, + Pair("全部磅单") { + Box(modifier = Modifier.fillMaxSize()) { + BaseQueryScreen(queryType = 3, showConfirm = true, showCancel = true, presenter = presenter2) + } + } + )) + } +} diff --git a/app/src/main/java/com/bbit/silk/ui/screen/core/ToConvertScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/core/ToConvertScreen.kt new file mode 100644 index 0000000..17e275e --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/core/ToConvertScreen.kt @@ -0,0 +1,41 @@ +package com.bbit.silk.ui.screen.core + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.base.BaseQueryScreen +import com.bbit.silk.base.MainFrame +import com.bbit.silk.viewmodel.DataViewModel +import com.blankj.utilcode.util.GsonUtils + +/** + * + * @Description 待茧别转换 + * @Author DuanKaiji + * @CreateTime 2024年04月30日 10:11:17 + */ +@Preview(showBackground = true) +@Composable +fun ToConvertPreview() { + ToConvertScreen(navController = rememberNavController()) +} + +@Composable +fun ToConvertScreen( + presenter: DataViewModel = viewModel(), + navController: NavController +) { + LaunchedEffect(Unit) { presenter.refreshAllType() } + MainFrame(title = "待茧别转换", presenter = presenter, navController = navController) { + BaseQueryScreen( + queryType = 6, + presenter = presenter + ) { item -> + // 根据需要定义点击事件,例如导航到某个路径或执行其他操作 + navController.navigate("main/toConvert/convert/${GsonUtils.toJson(item)}") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/core/ToTareScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/core/ToTareScreen.kt new file mode 100644 index 0000000..73b12b2 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/core/ToTareScreen.kt @@ -0,0 +1,56 @@ +package com.bbit.silk.ui.screen.core + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.base.BaseQueryByDate +import com.bbit.silk.base.BaseQueryScreen +import com.bbit.silk.base.ItemData +import com.bbit.silk.base.MainFrame +import com.bbit.silk.viewmodel.DataViewModel +import com.blankj.utilcode.constant.TimeConstants +import com.blankj.utilcode.util.GsonUtils +import com.blankj.utilcode.util.TimeUtils +import com.lt.compose_views.refresh_layout.RefreshContentStateEnum +import com.lt.compose_views.refresh_layout.VerticalRefreshableLayout +import com.lt.compose_views.refresh_layout.rememberRefreshLayoutState +import com.lt.compose_views.util.rememberMutableStateOf + +/** + * + * @Description 待扣皮定价 + * @Author DuanKaiji + * @CreateTime 2024年04月30日 10:11:17 + */ +@Preview(showBackground = true) +@Composable +fun ToTarePreview() { + ToTareScreen(navController = rememberNavController()) +} + +@Composable +fun ToTareScreen( + presenter: DataViewModel = viewModel(), + navController: NavController +) { + MainFrame(title = "待扣皮定价", presenter = presenter, navController = navController) { + BaseQueryScreen( + queryType = 1, + presenter = presenter + ) { item -> + navController.navigate("main/toTare/tare/${GsonUtils.toJson(item)}") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/core/TotalScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/core/TotalScreen.kt new file mode 100644 index 0000000..db960ed --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/core/TotalScreen.kt @@ -0,0 +1,77 @@ +package com.bbit.silk.ui.screen.core + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Divider +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.base.BaseQueryByDate +import com.bbit.silk.base.DynamicValuesRow +import com.bbit.silk.base.ListHeader +import com.bbit.silk.base.MainFrame +import com.bbit.silk.base.MyCard +import com.bbit.silk.base.NoData +import com.bbit.silk.viewmodel.DataViewModel +import com.blankj.utilcode.constant.TimeConstants +import com.blankj.utilcode.util.TimeUtils + +/** + * + * @Description 收购统计 + * @Author DuanKaiji + * @CreateTime 2024年04月30日 10:11:17 + */ +@Preview(showBackground = true) +@Composable +fun TotalPreview() { + TotalScreen(navController = rememberNavController()) +} + +@Composable +fun TotalScreen( + presenter: DataViewModel = viewModel(), + navController: NavController +) { + MainFrame(title = "收购统计", presenter = presenter, navController = navController) { + val startDate = + TimeUtils.date2String(TimeUtils.getDateByNow(-31, TimeConstants.DAY), "yyyy-MM-dd") + val endDate = TimeUtils.date2String(TimeUtils.getNowDate(), "yyyy-MM-dd") + LaunchedEffect(Unit) { + presenter.getTotalInfo(startDate, endDate) + } + Column { + BaseQueryByDate(startDate, endDate, false) { startDate, endDate, key -> + presenter.getTotalInfo(startDate, endDate) + } + MyCard(modifier = Modifier.padding(15.dp)) { + Column { + ListHeader(listOf("茧别", "重量", "均价", "金额合计")) + val totalInfo = presenter.totalInfo.collectAsState().value + totalInfo.items.forEach { + DynamicValuesRow(listOf(it.sgtypename, it.jingzhong, it.price, it.money)) + } + if (totalInfo.items.isNotEmpty()) { + Divider(modifier = Modifier.padding(vertical = 5.dp)) + DynamicValuesRow( + listOf( + "合计", + totalInfo.sumjingzhong, + totalInfo.price, + totalInfo.summoney + ) + ) + } else { + NoData() + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/core/UserScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/core/UserScreen.kt new file mode 100644 index 0000000..d727497 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/core/UserScreen.kt @@ -0,0 +1,182 @@ +package com.bbit.silk.ui.screen.core + +import BaseViewModel +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.R +import com.bbit.silk.base.BaseDoubleTextField +import com.bbit.silk.base.MainFrame +import com.bbit.silk.base.MyButton +import com.bbit.silk.base.MyCard +import com.bbit.silk.ui.view.ConfirmDialog +import com.bbit.silk.utils.MMKVUtil +import com.bbit.silk.utils.MyUtil +import com.bbit.silk.utils.database.TareDataBase +import com.bbit.silk.utils.global.Global +import com.bbit.silk.utils.global.SpinnerList +import kotlinx.coroutines.launch + +/** + * + * @Description 关于界面 + * @Author DuanKaiji + * @CreateTime 2024年04月30日 10:11:17 + */ +@Preview(showBackground = true) +@Composable +fun UserPreview() { + UserScreen(navController = rememberNavController()) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun UserScreen( + presenter: BaseViewModel = viewModel(), + navController: NavController +) { + val showExitToLogin = rememberSaveable { mutableStateOf(false) } + val showBottomSheet = rememberSaveable { mutableStateOf(false) } + val sheetState = rememberModalBottomSheetState() + val scope = rememberCoroutineScope() + ConfirmDialog( + title = "退出登录", + content = "确定要退出登录吗?", + showDialog = showExitToLogin.value, + onSuccess = { + showExitToLogin.value = false + MMKVUtil.put(Global.TOKEN, null) + MMKVUtil.put(Global.PASSWORD, null) + navController.navigate("login") { + popUpTo(navController.graph.startDestinationId) { inclusive = true } + launchSingleTop = true + } + }) { + showExitToLogin.value = false + } + MainFrame( + modifier = Modifier + .verticalScroll(rememberScrollState()), + title = "用户中心", + presenter = presenter, + navController = navController, + ) { + Box(modifier = Modifier.fillMaxWidth()) { + Image( + painter = painterResource(id = R.drawable.bg_user), contentDescription = null, + modifier = Modifier.fillMaxWidth(), + contentScale = ContentScale.Crop + ) + Column( + modifier = Modifier + .fillMaxSize() + .padding(15.dp) + ) { + Text(text = Global.getCompanyName(), color = Color.White, fontSize = 20f.sp) + Text(text = Global.getStationName(), color = Color.White) + Text(text = Global.getUserName(), color = Color.White) + MyCard(modifier = Modifier.padding(vertical = 20.dp)) { + Column(Modifier.padding(10.dp)) { + BaseDoubleTextField( + title = "默认定价单价", + justShowStr = Global.getUnit() + ">", + onClick = { showBottomSheet.value = true }) + Divider() + BaseDoubleTextField( + title = "关于", + justShowStr = ">", + onClick = { navController.navigate("about") }) + Divider() + BaseDoubleTextField(title = "清空缓存", justShowStr = ">", onClick = { + TareDataBase.removeCatch() + presenter.showTipsDialog("成功清空缓存") + }) + Divider() + BaseDoubleTextField( + title = "版本号", + justShowStr = MyUtil.getVersionName(), + onClick = {}) + Divider() + BaseDoubleTextField( + title = "授权信息", + justShowStr = Global.getCompanyId(), + onClick = {}) + } + } + MyButton( + onClick = { showExitToLogin.value = true }, + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + ) { + Text(text = "退出登录") + } + } + } + if (showBottomSheet.value) { + ModalBottomSheet( + onDismissRequest = { showBottomSheet.value = false }, + sheetState = sheetState, + dragHandle = {}, + ) { + BottomSheetContent( + title = "请选择默认定价单位", + options = SpinnerList.UNIT.toList(), + ) { + MMKVUtil.put(Global.UNIT, it) + scope.launch { sheetState.hide() } + .invokeOnCompletion { showBottomSheet.value = false } + } + } + } + } +} + +@Composable +fun BottomSheetContent( + title: String, + options: List, // 传递选项列表 + onSelect: (String) -> Unit +) { + Column(modifier = Modifier.padding(15.dp)) { + Text(modifier = Modifier.padding(bottom = 20.dp), text = title) + options.forEachIndexed { index, option -> + Text( + modifier = Modifier + .padding(vertical = 10.dp) + .fillMaxWidth() + .clickable { onSelect(option) }, + text = option + ) + // 如果当前不是最后一个选项,添加 Divider + if (index != options.lastIndex) { + Divider() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/coreFunc/ConvertScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/coreFunc/ConvertScreen.kt new file mode 100644 index 0000000..9aae982 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/coreFunc/ConvertScreen.kt @@ -0,0 +1,138 @@ +package com.bbit.silk.ui.screen.coreFunc + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.R +import com.bbit.silk.base.DynamicValuesRow +import com.bbit.silk.base.ItemData +import com.bbit.silk.base.ListHeader +import com.bbit.silk.base.MainFrame +import com.bbit.silk.base.MyButton +import com.bbit.silk.base.MyCard +import com.bbit.silk.model.QueryList +import com.bbit.silk.model.ToConvert +import com.bbit.silk.ui.screen.core.BottomSheetContent +import com.bbit.silk.utils.database.AllTypeDataBase +import com.bbit.silk.viewmodel.DataViewModel +import kotlinx.coroutines.launch + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年05月10日 11:22:30 + */ +@Preview(showBackground = true) +@Composable +fun ConvertPreview() { + ConvertScreen(QueryList.Data(), navController = rememberNavController()) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ConvertScreen( + data: QueryList.Data, + presenter: DataViewModel = viewModel(), + navController: NavController +) { + val convert = ToConvert(data.czSysid, data.items.map { item -> + ToConvert.Item( + oldsgtypesysid = item.sgTypeName, + newsgtypesysid = "" + ) + }) + val sheetState = rememberModalBottomSheetState() + val scope = rememberCoroutineScope() + val showBottomSheet = rememberSaveable { mutableStateOf(false) } + var selectedIndex by rememberSaveable { mutableStateOf(-1) } + MainFrame( + title = "茧别转换", + presenter = presenter, + navController = navController + ) { + Box(modifier = Modifier.fillMaxSize()) { + Image( + modifier = Modifier.fillMaxWidth(), + contentScale = ContentScale.Crop, + painter = painterResource(id = R.drawable.bg_user), + contentDescription = null + ) + Column { + ItemData( + name = data.nhName, + id = data.czCode, + state = data.status, + data = data.items + ) + MyCard(modifier = Modifier.padding(15.dp)) { + Column { + Column { + ListHeader(listOf("原茧别", "新茧别")) + } + // A位置的列表 + convert.items.forEachIndexed { index, it -> + DynamicValuesRow(listOf(it.oldsgtypesysid, it.newsgtypesysid)) { + // 弹出选择茧别的弹窗 + showBottomSheet.value = true + // 记录当前选择的项目索引 + selectedIndex = index + } + } + } + } + } + MyButton( + onClick = { + presenter.convert(navController, convert) + }, + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + .align(Alignment.BottomCenter) + ) { + Text(text = "确定转换") + } + if (showBottomSheet.value) { + ModalBottomSheet( + onDismissRequest = { showBottomSheet.value = false }, + sheetState = sheetState, + dragHandle = {}, + ) { + BottomSheetContent( + title = "请选择新茧别", + options = AllTypeDataBase.getAllTypeName() + ) { + convert.items[selectedIndex].newsgtypesysid = it + scope.launch { sheetState.hide() } + .invokeOnCompletion { showBottomSheet.value = false } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/coreFunc/TareScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/coreFunc/TareScreen.kt new file mode 100644 index 0000000..e93f751 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/coreFunc/TareScreen.kt @@ -0,0 +1,319 @@ +package com.bbit.silk.ui.screen.coreFunc + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.ScrollableTabRow +import androidx.compose.material3.Tab +import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.myapplication.ui.theme.MyColors +import com.bbit.silk.R +import com.bbit.silk.base.BaseDoubleTextField +import com.bbit.silk.base.ItemData +import com.bbit.silk.base.MainFrame +import com.bbit.silk.base.MyButton +import com.bbit.silk.model.QueryList +import com.bbit.silk.model.ToTareSubmit +import com.bbit.silk.ui.screen.core.BottomSheetContent +import com.bbit.silk.utils.MMKVUtil +import com.bbit.silk.utils.database.TareDataBase +import com.bbit.silk.utils.global.Global +import com.bbit.silk.utils.global.SpinnerList +import com.bbit.silk.viewmodel.DataViewModel +import kotlinx.coroutines.launch + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年05月10日 11:22:30 + */ +@Preview(showBackground = true) +@Composable +fun TarePreview() { + TareScreen(QueryList.Data(), navController = rememberNavController()) +} + +@Composable +fun TareScreen( + data: QueryList.Data, + presenter: DataViewModel = viewModel(), + navController: NavController +) { + var tare = remember { + ToTareSubmit(data.czCode, data.items.map { + val catchData = TareDataBase.getCatchById(data.czSysid + it.sgTypeSysid) + if (catchData != null && it.allowEditPrice != 0) { + // 如果有缓存数据则用缓存数据,其中必须允许编辑价格 防止出现不允许修改价格但应用了缓存价格的情况 + return@map catchData.copy(sgtypesysid = it.sgTypeSysid) + } else { + ToTareSubmit.Item(0.0, 0.0, it.price, it.sgTypeSysid) + } + }) + } + MainFrame(title = "扣皮定价", presenter = presenter, navController = navController) { + Box(modifier = Modifier.fillMaxSize()) { + Image( + modifier = Modifier.fillMaxWidth(), + contentScale = ContentScale.Crop, + painter = painterResource(id = R.drawable.bg_user), + contentDescription = null + ) + Column { + ItemData( + name = data.nhName, + id = data.czCode, + state = data.status, + data = data.items, + showCancel = true, + czsysid = data.czSysid, + navController = navController + ) + BaseScrollableTabRow(tare, data) { tare = it } + } + MyButton( + onClick = { presenter.tare(data, navController, tare) }, + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + .align(Alignment.BottomCenter) + ) { Text(text = "提交保存") } + } + } +} + + +@Preview(showBackground = true) +@Composable +fun ScrollableTabRowExamplePreview() { + BaseScrollableTabRow(ToTareSubmit(), QueryList.Data()) +} + +@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) +@Composable +fun BaseScrollableTabRow( + tareVal: ToTareSubmit, + data: QueryList.Data, + onTareChanged: (ToTareSubmit) -> Unit = {} +) { + val showBottomSheet = rememberSaveable { mutableStateOf(false) } + val sheetState = rememberModalBottomSheetState() + val scope = rememberCoroutineScope() + val tare by rememberSaveable { mutableStateOf(tareVal) } + val coroutineScope = rememberCoroutineScope() + val pagerState = rememberPagerState(pageCount = { data.items.size }) + LaunchedEffect(pagerState) { + snapshotFlow { pagerState.settledPage }.collect { page -> + } + } + Column( + modifier = Modifier + .fillMaxWidth() + .padding(15.dp, 0.dp, 15.dp, 70.dp) + ) { + Row { + ScrollableTabRow( + divider = {}, + edgePadding = 0.dp, + containerColor = MyColors.Transparent, + modifier = Modifier.weight(1f), + selectedTabIndex = pagerState.currentPage, + indicator = {} + ) { + data.items.forEachIndexed { index, data -> + Tab( + modifier = Modifier.background( + if (pagerState.currentPage == index) + Brush.verticalGradient( + colors = listOf(Color(0xFF9CFFD0), Color(0x80FFFFFF)) + ) + else + Brush.verticalGradient( + colors = listOf(Color(0x00FFFFFF), Color(0xFFFFFFFF)) + ) + ), + selected = pagerState.currentPage == index, + selectedContentColor = MyColors.Green, + unselectedContentColor = MyColors.Black, + onClick = { coroutineScope.launch { pagerState.scrollToPage(index) } }, + text = { Text(text = data.sgTypeName) } + ) + } + } + Row( + modifier = Modifier + .padding(start = 5.dp) + .wrapContentWidth() + .align(Alignment.CenterVertically) + .clickable { showBottomSheet.value = true } + ) { + Text(text = "单位:") + Text(text = Global.getUnit()) + Image( + modifier = Modifier + .padding(start = 2.dp) + .align(Alignment.CenterVertically), + painter = painterResource(id = R.drawable.down), + contentDescription = null, + ) + } + } + HorizontalPager(state = pagerState, userScrollEnabled = false, beyondBoundsPageCount = data.items.size) { selectedTabIndex -> + tarePage( + data.items[selectedTabIndex].baoshu.toString(), + data.items[selectedTabIndex].maozhong * Global.getUnitInt(), + tare.items[selectedTabIndex].pizhong * Global.getUnitInt(), + tare.items[selectedTabIndex].kouzhong * Global.getUnitInt(), + tare.items[selectedTabIndex].price / Global.getUnitInt(), + canEditPrice = (data.items[selectedTabIndex].allowEditPrice != 0) + ) { pizhong, kouzhong, price -> + tare.items[selectedTabIndex].pizhong = pizhong / Global.getUnitInt() + tare.items[selectedTabIndex].kouzhong = kouzhong / Global.getUnitInt() + tare.items[selectedTabIndex].price = price * Global.getUnitInt() + onTareChanged(tare) + val tempId = data.czSysid + data.items[selectedTabIndex].sgTypeSysid + TareDataBase.updateCatch(tare.items[selectedTabIndex].copy(sgtypesysid = tempId)) + } + } + if (showBottomSheet.value) { + ModalBottomSheet( + onDismissRequest = { showBottomSheet.value = false }, + sheetState = sheetState, + dragHandle = {}, + ) { + BottomSheetContent( + title = "请选择默认定价单位", + options = SpinnerList.UNIT.toList(), + ) { + MMKVUtil.put(Global.UNIT, it) + scope.launch { sheetState.hide() } + .invokeOnCompletion { showBottomSheet.value = false } + } + } + } + } +} + +@Composable +fun tarePage( + baoshu: String, + maozhong: Double, + pizhongDefault: Double, + kouzhongDefault: Double, + priceDefault: Double, + canEditPrice: Boolean = true, + onValueChanged: (pizhong: Double, kouzhong: Double, price: Double) -> Unit +) { + var pizhong by rememberSaveable { mutableStateOf(pizhongDefault) } + var kouzhong by rememberSaveable { mutableStateOf(kouzhongDefault) } + var price by rememberSaveable { mutableStateOf(priceDefault) } + LaunchedEffect(maozhong) { + // 毛重变化时(计价单位改变时) 响应更新数据 + onValueChanged(pizhong, kouzhong, price) + } + Column(modifier = Modifier.verticalScroll(rememberScrollState())) { + Card( + shape = RoundedCornerShape(0.dp, 10.dp, 10.dp, 10.dp), + colors = CardDefaults.cardColors(containerColor = if (isSystemInDarkTheme()) Color.DarkGray else Color.White) + ) { + BaseDoubleTextField( + title = "包数", + justShowStr = baoshu, + ) + BaseDoubleTextField( + title = "毛重", + justShowStr = maozhong.toString() + ) + BaseDoubleTextField( + startIcon = R.drawable.minus, + title = "皮重", + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + inputDefaultValue = pizhong.toString(), + ) { + pizhong = it.toDoubleOrNull() ?: 0.0 + onValueChanged(pizhong, kouzhong, price) + } + BaseDoubleTextField( + startIcon = R.drawable.minus, + title = "扣重", + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + inputDefaultValue = kouzhong.toString(), + ) { + kouzhong = it.toDoubleOrNull() ?: 0.0 + onValueChanged(pizhong, kouzhong, price) + } + BaseDoubleTextField( + startIcon = R.drawable.equal, + title = "净重", + justShowStr = if (maozhong - pizhong - kouzhong < 0) "数据异常" else (maozhong - pizhong - kouzhong).toString() + ) + } + Card( + colors = CardDefaults.cardColors(containerColor = if (isSystemInDarkTheme()) Color.DarkGray else Color.White), + modifier = Modifier.padding(top = 15.dp) + ) { + if (canEditPrice) { + BaseDoubleTextField( + startIcon = R.drawable.multi, + title = "单价(元/${Global.getUnit()})", + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + inputDefaultValue = price.toString() + ) { + price = it.toDoubleOrNull() ?: 0.0 + onValueChanged(pizhong, kouzhong, price) + } + } else { + BaseDoubleTextField( + startIcon = R.drawable.multi, + title = "单价(元/${Global.getUnit()})", + justShowStr = price.toString() + ) + } + BaseDoubleTextField( + title = "小计金额", + justShowStr = if (((maozhong - pizhong - kouzhong) * price) < 0) "数据异常" else ((maozhong - pizhong - kouzhong) * price).toString() + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/login/AboutScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/login/AboutScreen.kt new file mode 100644 index 0000000..e44fd77 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/login/AboutScreen.kt @@ -0,0 +1,82 @@ +package com.bbit.silk.ui.screen.login + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.base.ContentFrame +import com.bbit.silk.base.MainFrame +import com.bbit.silk.model.About +import com.bbit.silk.viewmodel.AboutViewModel + +@Preview(showBackground = true, widthDp = 400) +@Composable +fun AboutPreview() { + AboutScreen( + navController = rememberNavController() + ) +} + +@Composable +fun AboutScreen( + presenter: AboutViewModel = viewModel(), + navController: NavController +) { + MainFrame(title = "关于", navController = navController, presenter = presenter, content = { + Column( + modifier = Modifier + .fillMaxWidth() + ) { + ContentFrame("关于我们", content = { + Text(text = presenter.aboutInfo.collectAsState().value.about) + }) + ContentFrame("系统服务", content = { + presenter.aboutInfo.collectAsState().value.items.forEach { info(it) } + }) + } + }) +} + +/** + * 公司信息细则 + */ +@Composable +fun info(info: About.Data.Item) { + Column { + Text( + text = info.name, + fontSize = 20.sp, + modifier = Modifier.padding(bottom = 10.dp) + ) + LazyColumn { + items(info.items) { + Row { + Text( + text = it.name, + modifier = Modifier + .weight(1f) + ) + Text( + text = it.value, + modifier = Modifier + .wrapContentHeight() + .weight(1f) + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/screen/login/AuthScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/login/AuthScreen.kt new file mode 100644 index 0000000..642d362 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/login/AuthScreen.kt @@ -0,0 +1,161 @@ +package com.bbit.silk.ui.screen.login + +import androidx.compose.animation.animateContentSize +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material3.Button +import androidx.compose.material3.Divider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.R +import com.bbit.silk.base.ContentFrame +import com.bbit.silk.base.BaseDoubleTextField +import com.bbit.silk.base.MainFrame +import com.bbit.silk.base.MyButton +import com.bbit.silk.utils.global.Global +import com.bbit.silk.viewmodel.AuthViewModel + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月30日 10:11:17 + */ +@Preview(showBackground = true) +@Composable +fun AuthActivityPreview() { + AuthScreen(navController = rememberNavController()) +} + +@Composable +fun AuthScreen( + presenter: AuthViewModel = viewModel(), + navController: NavController +) { + MainFrame(title = "设备授权", presenter = presenter, navController = navController) { + if (presenter.notice.collectAsState().value == 0) { + unauthorized(presenter) + } else { + authorized(presenter.notice.collectAsState().value) + } + } +} + +/** + * 已授权界面 + */ +@Composable +fun authorized(state: Int? = 0) { + Column { + Column( + modifier = Modifier.padding(vertical = 100.dp), + ) { + Image( + painter = painterResource( + id = if (state == 1) { + R.drawable.check_success + } else { + R.drawable.tips + } + ), + contentDescription = null, + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .size(70.dp) + ) + Text( + text = if (state == 1) { + "已授权" + } else { + "待授权" + }, + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + textAlign = TextAlign.Center, // 居中对齐 + ) + } + ContentFrame("授权说明") { + Column { + BaseDoubleTextField(title = "公司编号", justShowStr = Global.getCompanyId()) + Divider() + BaseDoubleTextField(title = "申请人", justShowStr = Global.getRegName()) + Divider() + BaseDoubleTextField(title = "电话号码", justShowStr = Global.getRegTel()) + } + } + } +} + +/** + * 未授权界面 + */ +@Composable +fun unauthorized( + presenter: AuthViewModel = viewModel() +) { + Column { + //企业编号,申请人,电话号码,设备码,PWD + var companyId by remember { mutableStateOf("") } + var applicant by remember { mutableStateOf("") } + var phone by remember { mutableStateOf("") } + var pwd by remember { mutableStateOf("") } + var showPwd by rememberSaveable { mutableStateOf(false) } + ContentFrame("授权说明") { + Text(text = "本设备未获得授权无法连接系统,需申请授权后才允许合法登录。") + } + ContentFrame("授权说明") { + Column( + modifier = Modifier + .animateContentSize( + animationSpec = spring( + dampingRatio = Spring.DampingRatioMediumBouncy, + stiffness = Spring.StiffnessLow + ) + ) + ) { + BaseDoubleTextField(title = "企业编号") { companyId = it } + BaseDoubleTextField(title = "申请人") { applicant = it } + BaseDoubleTextField(title = "电话号码") { phone = it } + BaseDoubleTextField( + title = "设备码", + justShowStr = Global.getDeviceId(), + onClick = { + showPwd = !showPwd + }) + if (showPwd) { + BaseDoubleTextField(title = "PWD(可选)") { pwd = it } + } + } + } + MyButton( + onClick = { presenter.auth(companyId, applicant, phone, pwd) }, + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + ) { + Text("申请授权") + } + } +} diff --git a/app/src/main/java/com/bbit/silk/ui/screen/login/LoginScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/login/LoginScreen.kt new file mode 100644 index 0000000..8e1d096 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/login/LoginScreen.kt @@ -0,0 +1,354 @@ +package com.bbit.silk.ui.screen.login + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Clear +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff +import androidx.compose.material.icons.outlined.Clear +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.R +import com.bbit.silk.base.MyButton +import com.bbit.silk.base.MyCard +import com.bbit.silk.base.MyGreenCard +import com.bbit.silk.base.MyTextField +import com.bbit.silk.ui.view.ConfirmDialog +import com.bbit.silk.ui.view.InputDialog +import com.bbit.silk.ui.view.LoadingDialog +import com.bbit.silk.ui.view.LoadingDialogData +import com.bbit.silk.ui.view.TipsDialog +import com.bbit.silk.utils.MMKVUtil +import com.bbit.silk.utils.global.Global +import com.bbit.silk.viewmodel.LoginViewModel +import com.blankj.utilcode.util.AppUtils +import com.lt.compose_views.text_field.HintComposeWithTextField +import com.lt.compose_views.text_field.PasswordTextField +import java.util.Locale + +@Preview(showBackground = true, widthDp = 400) +@Composable +fun MyPreview() { + LoginScreen( + versionName = "1.0.0", + usernameDefault = "15398380348", + companyIdVal = "GXJIALIAN", + modifier = Modifier.fillMaxSize(), + navController = rememberNavController() + ) +} + +@Composable +fun LoginScreen( + modifier: Modifier = Modifier, + usernameDefault: String, + versionName: String, + companyIdVal: String, + presenter: LoginViewModel = viewModel(), + navController: NavController +) { + presenter.checkPermission(LocalContext.current) + if (presenter.getInMainScreen.collectAsState().value) { + navController.navigate("main") { + popUpTo(navController.graph.startDestinationId) { inclusive = true } + launchSingleTop = true + } + presenter.resetGetInMainScreen() + } + var showExitDialog by rememberSaveable { mutableStateOf(false) } + ConfirmDialog( + title = "提示", + content = "是否关闭程序?", + showDialog = showExitDialog, + onSuccess = { + AppUtils.exitApp() + }, + onDismiss = { showExitDialog = false }) + BackHandler { + showExitDialog = true + } + Surface( + modifier = modifier.fillMaxSize() + ) { + var companyId by rememberSaveable { mutableStateOf(companyIdVal) } + var passwordHidden by rememberSaveable { mutableStateOf(true) } + var username by rememberSaveable { mutableStateOf(usernameDefault) } + var password by remember { mutableStateOf("") } + var showInputDialog by remember { mutableStateOf(false) } + TipsDialog( + showDialog = presenter.tipsDialog.collectAsState().value.showDialog, + onDismiss = { presenter.hideTipsDialog() }, + content = presenter.tipsDialog.collectAsState().value.content + ) + InputDialog( + title = "企业编号", + showDialog = showInputDialog, + onDismiss = { showInputDialog = false }) { + companyId = it.uppercase(Locale.getDefault()) + MMKVUtil.put(Global.COMPANY_ID, companyId) + showInputDialog = false + } + LoadingDialog( + LoadingDialogData( + showDialog = presenter.loadingDialog.collectAsState().value.showDialog, + content = presenter.loadingDialog.collectAsState().value.content + ) + ) + Box { + Image( + painter = painterResource(id = R.drawable.bg_login), + contentDescription = "Login background", + contentScale = ContentScale.Crop, + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + ) + Column( + modifier = Modifier + .padding(top = 40.dp) + ) { + Image( + painter = painterResource(id = R.drawable.logo), + contentDescription = null, + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + ) + Text( + text = "智慧蚕桑-掌上收购终端", + fontWeight = androidx.compose.ui.text.font.FontWeight.Bold, + color = Color.White, + fontSize = 24.sp, // 指定字体大小 + textAlign = TextAlign.Center, // 居中对齐 + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp) // 添加顶部内边距 + ) + MyCard( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp, vertical = 10.dp) + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + MyGreenCard( + modifier = Modifier + .fillMaxWidth() + .longClick { + showInputDialog = true + }, + ) { + Row( + modifier = Modifier.padding(10.dp) + ) { + Text("企业编号:", color = Color(0xFF009140), + modifier = Modifier.align(Alignment.CenterVertically)) + Text( + companyId, + color = Color(0xFF009140), + modifier = Modifier.align(Alignment.CenterVertically) + ) + } + } + MyTextField( + value = username, + hint ="请输入账号", + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 10.dp), +// trailing = { +// Icon( +// Icons.Outlined.Clear, +// contentDescription = "清空账号", +// modifier = Modifier.clickable { +// username = "" +// } +// ) +// }, + onValueChange = { username = it }, + ) + PasswordTextField( + hint = HintComposeWithTextField.createTextHintCompose("请输入密码"), + modifier = Modifier.height(50.dp), + value = password, + onValueChange = { + password = it + }, + passwordIsShow = !passwordHidden, + onPasswordIsShowChange = { + passwordHidden = !it + } + ) + MyButton( + onClick = { + presenter.login(username, password) + }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp) + ) { + Text("登录") + } + Text( + text = "版本号:" + versionName, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() + ) + } + } + MyCard( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp, vertical = 10.dp) + ) { + Text( + text = "1、请保管好设备,如有遗失,立即报备。\n" + + "2、登录前,请检查版本是否为最新版本。\n" + + "3、技术支持:四川主干信息技术有限公司。\n" + + "4、技术服务热线:028-87676865(直拨)。", + fontSize = 14.sp, + textAlign = TextAlign.Start, + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + ) + } + MyCard( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp, vertical = 10.dp) + ) { + Row { + MyImageButton( + modifier = Modifier.weight(1f), + text = "设备授权", + image = R.drawable.device, + onClick = { navController.navigate("auth") }) + MyImageButton( + modifier = Modifier.weight(1f), + text = "关于我们", + image = R.drawable.info, + onClick = { navController.navigate("about") }) + MyImageButton( + modifier = Modifier.weight(1f), + text = "检查更新", + image = R.drawable.check, + onClick = { navController.navigate("update") }) + MyImageButton( + modifier = Modifier.weight(1f), + text = "忘记密码", + image = R.drawable.password, + onClick = { + presenter.showTipsDialog( + "PDA暂不支持修改密码,请通过电脑登录您的账号后," + + "在【个人中心】修改密码,电脑端修改后,手机端同步生效。" + ) + }) + } + } + } + } + } +} + +@Preview( + showBackground = true, + widthDp = 400 +) +@Composable +fun MyImageButtonPreview(modifier: Modifier = Modifier) { + Column( + modifier = modifier + ) { + MyImageButton( + modifier = Modifier.fillMaxWidth(), + text = "首页", + image = R.drawable.logo, + onClick = {}) + } +} + +/** + * 自定义ImageButton + */ +@Composable +fun MyImageButton( + text: String, + image: Int, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .clickable { onClick() } + .fillMaxWidth() + ) { + Image( + painter = painterResource(id = image), + contentDescription = null, + modifier = Modifier + .padding(10.dp) + .fillMaxWidth() + ) + Text( + text = text, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 5.dp) + ) + } +} + +/** + * 长按事件 + */ +fun Modifier.longClick(onLongClick: (Offset) -> Unit): Modifier = pointerInput(this) { + detectTapGestures( + onLongPress = onLongClick + ) +} diff --git a/app/src/main/java/com/bbit/silk/ui/screen/login/UpdateScreen.kt b/app/src/main/java/com/bbit/silk/ui/screen/login/UpdateScreen.kt new file mode 100644 index 0000000..0c6b18b --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/screen/login/UpdateScreen.kt @@ -0,0 +1,86 @@ +package com.bbit.silk.ui.screen.login + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.bbit.silk.base.BaseDoubleTextField +import com.bbit.silk.base.ContentFrame +import com.bbit.silk.base.MainFrame +import com.bbit.silk.base.MyButton +import com.bbit.silk.ui.view.ConfirmDialog +import com.bbit.silk.utils.MyUtil +import com.bbit.silk.viewmodel.UpdateViewModel + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月30日 10:11:17 + */ +@Preview(showBackground = true) +@Composable +fun UpdateActivityPreview() { + UpdateScreen(UpdateViewModel(), rememberNavController()) +} + +@Composable +fun UpdateScreen( + presenter: UpdateViewModel = viewModel(), + navController: NavController +) { + val showUpdateDialog = remember { mutableStateOf(false) } + val btnUpdateState = remember { mutableStateOf(false) } + val versionDescription = remember { mutableStateOf("") } + ConfirmDialog( + title = "更新", + content = versionDescription.value, + showDialog = showUpdateDialog.value, + onSuccess = { + //下载更新 + showUpdateDialog.value = false + presenter.downFile() + }) { + showUpdateDialog.value = false + } + val versionInfo = presenter.updateInfo.collectAsState().value + if (versionInfo.versionNumber > MyUtil.getVersionId()) { + //可以升级 + versionDescription.value = versionInfo.versionDescription + btnUpdateState.value = true + } else { + btnUpdateState.value = false + } + MainFrame(title = "检测升级", presenter = presenter, navController = navController) { + Column { + ContentFrame(title = "版本信息") { + Column { + BaseDoubleTextField( + title = "当前版本", + justShowStr = MyUtil.getVersionName() + ) + BaseDoubleTextField(title = "最新版本", justShowStr = versionInfo.versionName) + } + } + MyButton( + enabled = btnUpdateState.value, + onClick = { showUpdateDialog.value = true }, + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + ) { + Text(if (btnUpdateState.value) "更新" else "已是最新版本") + } + } + } +} diff --git a/app/src/main/java/com/bbit/silk/ui/theme/Color.kt b/app/src/main/java/com/bbit/silk/ui/theme/Color.kt new file mode 100644 index 0000000..50fba0d --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/theme/Color.kt @@ -0,0 +1,21 @@ +package com.bbit.myapplication.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) + +object MyColors { + val Transparent = Color(0x00000000) + val Green = Color(0xFF209344) + val White = Color.White + val Black = Color.Black + val Blue = Color.Blue + val Red = Color.Red + // 添加更多的颜色常量... +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/theme/Theme.kt b/app/src/main/java/com/bbit/silk/ui/theme/Theme.kt new file mode 100644 index 0000000..0b24313 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/theme/Theme.kt @@ -0,0 +1,56 @@ +package com.bbit.myapplication.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun AppTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/theme/Type.kt b/app/src/main/java/com/bbit/silk/ui/theme/Type.kt new file mode 100644 index 0000000..26e158f --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.bbit.myapplication.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/view/ConfirmDialog.kt b/app/src/main/java/com/bbit/silk/ui/view/ConfirmDialog.kt new file mode 100644 index 0000000..37513c9 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/view/ConfirmDialog.kt @@ -0,0 +1,138 @@ +package com.bbit.silk.ui.view + +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material3.Card +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.bbit.myapplication.ui.theme.MyColors + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月30日 08:54:51 + */ +@Preview(showBackground = true) +@Composable +fun ConfirmDialogPreview() { + ConfirmDialog( + title = "确认框", + content = "这是一个确认框", + showDialog = true, + onSuccess = {}, + onDismiss = {} + ) +} + +@Composable +fun ConfirmDialog( + title: String, + content: String, + canManualClose: Boolean = true, + showDialog: Boolean, + onSuccess: () -> Unit, + onDismiss: () -> Unit = {} +) { + //官方提供的弹窗 +// if (showDialog) { +// AlertDialog( +// title = { Text(text = title) }, +// text = { Text(text = content) }, +// confirmButton = { +// TextButton( +// onClick = { +// onSuccess() +// } +// ) { +// Text(color = MyColors.Green, text = "确定") +// } +// }, +// onDismissRequest = { +// if (canManualClose) { +// onDismiss() +// } +// }, +// dismissButton = { +// if (canManualClose) { +// TextButton( +// onClick = { +// onDismiss() +// } +// ) { +// Text(color = MyColors.Green, text = "取消") +// } +// } +// }) +// } + if (showDialog) { + Dialog( + onDismissRequest = { + if (canManualClose) { + onDismiss() + } + } + ) { + Column { + Card { + Column( + modifier = Modifier + .wrapContentWidth() + .background(if (isSystemInDarkTheme()) Color.DarkGray else Color.White) + .padding(20.dp) + ) { + Text( + text = title, + // 设置文字为标题样式 + style = MaterialTheme.typography.headlineMedium + ) + Text( + text = content, + modifier = Modifier + .padding(vertical = 20.dp) + .widthIn(300.dp) + ) + Row( + modifier = Modifier + .wrapContentWidth() + .align(Alignment.End) + ) { + TextButton( + onClick = { + onSuccess() + }, + modifier = Modifier + .padding(end = 10.dp) + .wrapContentWidth() + ) { + Text(color = MyColors.Green, text = "确定") + } + if (canManualClose) { + TextButton( + onClick = onDismiss, + modifier = Modifier + .wrapContentWidth() + ) { + Text(color = MyColors.Green, text = "取消") + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/view/InputDialog.kt b/app/src/main/java/com/bbit/silk/ui/view/InputDialog.kt new file mode 100644 index 0000000..98dd8b7 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/view/InputDialog.kt @@ -0,0 +1,128 @@ +package com.bbit.silk.ui.view + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Clear +import androidx.compose.material3.Card +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.bbit.silk.base.MyButton +import com.bbit.silk.base.MyTextField + +data class InputDialogData( + var showDialog: Boolean = false, + var title: String = "", +) + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月30日 08:54:51 + */ +@Preview(showBackground = true) +@Composable +fun InputDialogPreview() { + InputDialog( + title = "公司编号", + showDialog = true, + onSuccess = {} + ) +} + +@Composable +fun InputDialog( + title: String, + defaultValue: String = "", + showDialog: Boolean, + onDismiss: () -> Unit = {},//只是关闭的方法 + onSuccess: (String) -> Unit//确定方法 +) { + var content by rememberSaveable { mutableStateOf(defaultValue) } +// if (showDialog) { + AnimatedVisibility(showDialog) { + Dialog(onDismissRequest = { onDismiss() }) { + Column { + Card { + Column( + modifier = Modifier + .wrapContentWidth() + .background(Color.White) + .padding(horizontal = 20.dp, vertical = 10.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .heightIn(max = 25.dp) + ) { + // 一个绿色的竖线 + Box( + modifier = Modifier + .width(3.dp) + .fillMaxHeight() + .background(Color(0xFF209344)) + ) + Text( + text = title, + modifier = Modifier + .wrapContentHeight() + .padding(start = 10.dp) + .align(Alignment.CenterVertically) + ) + } + MyTextField( + hint = "请输入" + title, + value = content, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 20.dp), + trailing = { + Icon( + Icons.Filled.Clear, + contentDescription = "清空", + modifier = Modifier.clickable { + content = "" + } + ) + }, + onValueChange = { content = it } + ) + MyButton( + onClick = { + onSuccess(content) + }, + modifier = Modifier + .wrapContentWidth() + .align(Alignment.End) + ) { + Text("确定") + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/view/LoadingDialog.kt b/app/src/main/java/com/bbit/silk/ui/view/LoadingDialog.kt new file mode 100644 index 0000000..f4ebfa7 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/view/LoadingDialog.kt @@ -0,0 +1,92 @@ +package com.bbit.silk.ui.view + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material3.Card +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog + +/** + * + * @Description 加载弹窗(包括无限加载与指定加载) + * @Author DuanKaiji + * @CreateTime 2024年04月29日 09:09:42 + */ +data class LoadingDialogData( + var showProcess: Boolean = false, + var process: Int = 0, + var showDialog: Boolean = false, + var content: String = "", +) + +@Preview(showBackground = true) +@Composable +fun LoadingDialogPreview() { + LoadingDialog( + LoadingDialogData( + showDialog = true, + content = "正在加载中" + ) + ) +} + +@Composable +fun LoadingDialog( + loadingDialogData: LoadingDialogData +) { + AnimatedVisibility(loadingDialogData.showDialog) { +// if (loadingDialogData.showDialog) { + Dialog(onDismissRequest = { }) { + // 使用 Column 布局来自定义弹窗内容 + Column { + Card(modifier = Modifier.padding(bottom = 16.dp)) { + Column( + modifier = Modifier + .wrapContentWidth() + .background(Color.White) + .padding(30.dp) + ) { + if (loadingDialogData.showProcess) { + LinearProgressIndicator( + modifier = Modifier + .width(200.dp) + .align(Alignment.CenterHorizontally), + progress = loadingDialogData.process / 100f + ) + } else { + CircularProgressIndicator( + modifier = Modifier + .width(40.dp) + .align(Alignment.CenterHorizontally), + color = MaterialTheme.colorScheme.primary, + trackColor = MaterialTheme.colorScheme.surfaceVariant, + ) + } + Text( + text = loadingDialogData.content, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(top = 20.dp) + .widthIn(200.dp) + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/ui/view/TipsDialog.kt b/app/src/main/java/com/bbit/silk/ui/view/TipsDialog.kt new file mode 100644 index 0000000..73eec39 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/ui/view/TipsDialog.kt @@ -0,0 +1,93 @@ +package com.bbit.silk.ui.view + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material3.Card +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.bbit.silk.R + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月29日 09:09:42 + */ +data class TipsDialogData( + var showDialog: Boolean = false, + var content: String = "", +) + +@Preview(showBackground = true) +@Composable +fun TipsDialogPreview() { + TipsDialog( + content = "这是一个提示框", + showDialog = true, + onDismiss = {} + ) +} + +@Composable +fun TipsDialog( + content: String, + showDialog: Boolean, + onDismiss: () -> Unit +) { + if (showDialog) { + Dialog(onDismissRequest = onDismiss) { + // 使用 Column 布局来自定义弹窗内容 + Column { + Card(modifier = Modifier.padding(bottom = 12.dp)) { + Column( + modifier = Modifier + .wrapContentWidth() + .background(Color.White) + .padding(20.dp) + ) { + Image( + painter = painterResource(id = R.drawable.tips), + contentDescription = "Tips", + modifier = Modifier + .padding(bottom = 18.dp) + .wrapContentWidth() + .align(Alignment.CenterHorizontally) + ) + Text( + text = content, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(vertical = 10.dp) + .widthIn(200.dp) + ) + } + } + Image( + painter = painterResource(id = R.drawable.dismiss), + contentDescription = "Close", + contentScale = ContentScale.Crop, + modifier = Modifier + .size(30.dp) + .wrapContentWidth() + .clickable { onDismiss() } + .align(Alignment.CenterHorizontally) + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/utils/MMKVUtil.java b/app/src/main/java/com/bbit/silk/utils/MMKVUtil.java new file mode 100644 index 0000000..7cddd1a --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/MMKVUtil.java @@ -0,0 +1,129 @@ +package com.bbit.silk.utils; + + +import android.os.Parcelable; +import com.blankj.utilcode.util.GsonUtils; +import com.tencent.mmkv.MMKV; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * MMKV工具类 + */ +public class MMKVUtil { + private static MMKVUtil INSTANCE; + private static MMKV mmkvInstance; + + private MMKVUtil() { + } + + /** + * 初始化MMKV,只能在Application中初始化一次 + */ + public static void init() { + INSTANCE = new MMKVUtil(); + mmkvInstance = MMKV.defaultMMKV(); + } + + /** + * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法 + */ + public static void put(String key, T object) { + if (object instanceof String) { + mmkvInstance.encode(key, (String) object); + } else if (object instanceof Integer) { + mmkvInstance.encode(key, (Integer) object); + } else if (object instanceof Boolean) { + mmkvInstance.encode(key, (Boolean) object); + } else if (object instanceof Float) { + mmkvInstance.encode(key, (Float) object); + } else if (object instanceof Long) { + mmkvInstance.encode(key, (Long) object); + } else if (object instanceof Double) { + mmkvInstance.encode(key, (Double) object); + } else if (object instanceof Set) { + mmkvInstance.encode(key, (Set) object); + } else if (object instanceof Parcelable) { + mmkvInstance.encode(key, (Parcelable) object); + } else { + mmkvInstance.encode(key, object == null ? "" : object.toString()); + } + } + + /** + * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值 + */ + public static T get(String key, T defaultObject) { + if (defaultObject instanceof String || defaultObject == null) { + return (T) mmkvInstance.decodeString(key, (String) defaultObject); + } else if (defaultObject instanceof Integer) { + return (T) Integer.valueOf(mmkvInstance.decodeInt(key, (Integer) defaultObject)); + } else if (defaultObject instanceof Boolean) { + return (T) Boolean.valueOf(mmkvInstance.decodeBool(key, (Boolean) defaultObject)); + } else if (defaultObject instanceof Float) { + return (T) Float.valueOf(mmkvInstance.decodeFloat(key, (Float) defaultObject)); + } else if (defaultObject instanceof Long) { + return (T) Long.valueOf(mmkvInstance.decodeLong(key, (Long) defaultObject)); + } else if (defaultObject instanceof Double) { + return (T) Double.valueOf(mmkvInstance.decodeDouble(key, (Double) defaultObject)); + } else if (defaultObject instanceof Parcelable) { + Parcelable p = (Parcelable) defaultObject; + return (T) mmkvInstance.decodeParcelable(key, p.getClass()); + } else { + return null; + } + } + + /** + * 获得字符串 + */ + public static String get(String key) { + return mmkvInstance.decodeString(key, ""); + } + + /** + * 移除某个key值已经对应的值 + */ + public void remove(String key) { + mmkvInstance.remove(key); + } + + /** + * 查询某个key是否已经存在 + */ + public boolean contains(String key) { + return mmkvInstance.contains(key); + } + + /** + * 清除所有数据 + */ + public static void clear() { + mmkvInstance.clear(); + } + + /** + * 获取所有key-value的json字符串 + */ + public static String getAllKeyValues() { + Map result = new HashMap<>(); + String[] keys = mmkvInstance.allKeys(); + if (keys == null || keys.length == 0) { + return ""; + } + for (String key : keys) { + if (key.contains("HISTORY") || key.contains("user") || key.contains("password")) { + continue; + } + //将所有的key-value转换成json字符串 + result.put(key, mmkvInstance.decodeString(key, "")); + //解决boolean、int等基本类型无法转换成json字符串的问题 + if (result.get(key) == null) { + result.put(key, mmkvInstance.decodeInt(key, 0)); + } + } + return GsonUtils.toJson(result); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/utils/MyUtil.java b/app/src/main/java/com/bbit/silk/utils/MyUtil.java new file mode 100644 index 0000000..a2ce60d --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/MyUtil.java @@ -0,0 +1,101 @@ +package com.bbit.silk.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.view.View; +import android.view.animation.LinearInterpolator; + +import com.bbit.silk.MyApp; +import com.bbit.silk.model.Login; +import com.bbit.silk.model.Weather; +import com.bbit.silk.utils.global.Global; +import com.bbit.silk.utils.log.MyLog; +import com.bbit.silk.utils.network.Url; +import com.bbit.silk.utils.network.XHttpManager; +import com.bbit.silk.utils.network.XHttpShorthand; +import com.blankj.utilcode.util.AppUtils; +import com.blankj.utilcode.util.EncryptUtils; +import com.blankj.utilcode.util.TimeUtils; +import org.xutils.http.RequestParams; +import org.xutils.x; +public class MyUtil { + + /** + * 获取当前版本号 + */ + public static int getVersionId() { + try { + PackageManager packageManager = MyApp.getAppContext().getPackageManager(); + PackageInfo packageInfo = packageManager.getPackageInfo(MyApp.getAppContext().getPackageName(), 0); + return packageInfo.versionCode; + } catch (Exception e) { + e.printStackTrace(); + return -1; + } + } + + /** + * 静默登录 + */ + public static void login(Runnable runnable) { + RequestParams params = XHttpManager.getInstance().getRequestParams(Url.login, false); + params.addParameter("Platform", "1"); + params.addParameter("TenantCode", Global.getCompanyId()); + params.addParameter("HardwareId", Global.getDeviceId()); + params.addParameter("Account", Global.getUserAccount()); + params.addParameter("Password", EncryptUtils.encryptMD5ToString(Global.getPassword())); + x.http().post(params, new XHttpShorthand() { + @Override + public void success(Login model) { + MyLog.app("登录成功"); + if (model.getResult()) { + MMKVUtil.put(Global.TOKEN, model.getData().getTokenType() + " " + model.getData().getAccessToken()); + MMKVUtil.put(Global.TOKEN_TIME, TimeUtils.string2Millis(model.getData().getExpireTime())); + } + if (runnable != null) { + runnable.run(); + } + } + + @Override + public void error(Throwable e) { + MyLog.appError("Token获取失败"); + } + + }); + } + + /** + * 获取当前版本名称 + */ + public static String getVersionName() { + try { + PackageManager packageManager = MyApp.getAppContext().getPackageManager(); + PackageInfo packageInfo = packageManager.getPackageInfo(MyApp.getAppContext().getPackageName(), 0); + return packageInfo.versionName; + } catch (Exception e) { + e.printStackTrace(); + return "Err"; + } + } + + /** + * 获取温度和天气信息的格式化字符串。 + * + * @param castsDTO 包含天气信息的对象。 + * @return 格式化后的温度和天气信息字符串。 + */ + public static String formatTemperatureAndWeather(Weather.Data.Cast castsDTO) { + // 将白天和晚上的温度进行比较 + int dayTemp = Integer.parseInt(castsDTO.getDaytemp()); + int nightTemp = Integer.parseInt(castsDTO.getNighttemp()); + int minTemp = Math.min(dayTemp, nightTemp); + int maxTemp = Math.max(dayTemp, nightTemp); + // 组合温度和天气信息 + String formattedString = minTemp + "~" + maxTemp + "℃ " + castsDTO.getDayweather(); + return formattedString; + } + +} diff --git a/app/src/main/java/com/bbit/silk/utils/database/AllTypeDataBase.java b/app/src/main/java/com/bbit/silk/utils/database/AllTypeDataBase.java new file mode 100644 index 0000000..10e74b9 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/database/AllTypeDataBase.java @@ -0,0 +1,59 @@ +package com.bbit.silk.utils.database; + +import com.bbit.silk.model.AllType; +import com.bbit.silk.utils.MMKVUtil; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月03日 15:20:10 + */ +public class AllTypeDataBase { + + public static final String ALL_TYPE = "ALL_TYPE"; + + public static void setAllType(List temp) { + MMKVUtil.put(ALL_TYPE, new Gson().toJson(temp)); + } + + public static String getSysIdByName(String name) { + String json = MMKVUtil.get(ALL_TYPE, "[]"); + List temp = new Gson().fromJson(json, new TypeToken>() { + }.getType()); + for(AllType.Data dataDTO : temp) { + if(dataDTO.getName().equals(name)) { + return dataDTO.getSysid(); + } + } + return null; + } + + public static String getNameBySysId(String sysId) { + String json = MMKVUtil.get(ALL_TYPE, "[]"); + List temp = new Gson().fromJson(json, new TypeToken>() { + }.getType()); + for(AllType.Data dataDTO : temp) { + if(dataDTO.getSysid().equals(sysId)) { + return dataDTO.getName(); + } + } + return null; + } + + public static List getAllTypeName() { + String json = MMKVUtil.get(ALL_TYPE, "[]"); + List temp = new Gson().fromJson(json, new TypeToken>() { + }.getType()); + List result = new ArrayList<>(); + for(AllType.Data dataDTO : temp) { + result.add(dataDTO.getName()); + } + return result; + } + +} diff --git a/app/src/main/java/com/bbit/silk/utils/database/PriceDataBase.java b/app/src/main/java/com/bbit/silk/utils/database/PriceDataBase.java new file mode 100644 index 0000000..6afc5a5 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/database/PriceDataBase.java @@ -0,0 +1,47 @@ +package com.bbit.silk.utils.database; + +import com.bbit.silk.model.TodayPrice; +import com.bbit.silk.utils.MMKVUtil; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.util.List; + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月03日 15:20:10 + */ +public class PriceDataBase { + + public static final String PRICE_CATCH = "PRICE_CATCH"; + + + /** + * 获取缓存 + * + * @return 最小值,最大值 + */ + public static double[] getCatchById(String name) { + String json = MMKVUtil.get(PRICE_CATCH, "[]"); + List temp = new Gson().fromJson(json, new TypeToken>() { + }.getType()); + for (TodayPrice.Data.Item t : temp) { + if (t.getName().equals(name)) { + return new double[]{Double.parseDouble(t.getMinprice()), Double.parseDouble(t.getMaxprice())}; + } + } + return new double[]{0,0}; + } + + /** + * 更新缓存 + * 注意:sgtypesysid + * + * @param data + */ + public static void updateCatch(List data) { + MMKVUtil.put(PRICE_CATCH, new Gson().toJson(data)); + } + +} diff --git a/app/src/main/java/com/bbit/silk/utils/database/TareDataBase.java b/app/src/main/java/com/bbit/silk/utils/database/TareDataBase.java new file mode 100644 index 0000000..5d58fc8 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/database/TareDataBase.java @@ -0,0 +1,88 @@ +package com.bbit.silk.utils.database; + +import com.bbit.silk.model.QueryList; +import com.bbit.silk.model.ToTareSubmit; +import com.bbit.silk.utils.MMKVUtil; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.util.Iterator; +import java.util.List; + +/** + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年04月03日 15:20:10 + */ +public class TareDataBase { + + public static final String TARE_CATCH = "TARE_CATCH"; + + + /** + * 获取缓存 + * + * @return + */ + public static ToTareSubmit.Item getCatchById(String id) { + String json = MMKVUtil.get(TARE_CATCH, "[]"); + List temp = new Gson().fromJson(json, new TypeToken>() { + }.getType()); + for (ToTareSubmit.Item itemsDTO : temp) { + if (itemsDTO.getSgtypesysid().equals(id)) { + return itemsDTO; + } + } + return null; + } + + /** + * 更新缓存 + * 注意:sgtypesysid + * + * @param data + */ + public static void updateCatch(ToTareSubmit.Item data) { + String json = MMKVUtil.get(TARE_CATCH, "[]"); + List temp = new Gson().fromJson(json, new TypeToken>() { + }.getType()); + //判断是否有重复 则删除重复数据 + for (int i = 0; i < temp.size(); i++) { + if (temp.get(i).equals(data)) { + temp.remove(i); + break; + } + } + temp.add(data); + MMKVUtil.put(TARE_CATCH, new Gson().toJson(temp)); + } + + /** + * 清除缓存 + */ + public static void removeCatch() { + MMKVUtil.put(TARE_CATCH, "[]"); + } + + /** + * 清除指定缓存 + */ + public static void removeCatchById(QueryList.Data dataDTO) { + String json = MMKVUtil.get(TARE_CATCH, "[]"); + List temp = new Gson().fromJson(json, new TypeToken>() { + }.getType()); + // 涉及列表删除 使用迭代器进行删除 + Iterator iterator = temp.iterator(); + while (iterator.hasNext()) { + ToTareSubmit.Item item = iterator.next(); + for (QueryList.Data.Item itemsDTO : dataDTO.getItems()) { + if (item.getSgtypesysid().equals(dataDTO.getCzSysid() + itemsDTO.getSgTypeSysid())) { + iterator.remove(); + break; + } + } + } + MMKVUtil.put(TARE_CATCH, new Gson().toJson(temp)); + } + +} diff --git a/app/src/main/java/com/bbit/silk/utils/global/Global.java b/app/src/main/java/com/bbit/silk/utils/global/Global.java new file mode 100644 index 0000000..f2e39f5 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/global/Global.java @@ -0,0 +1,125 @@ +package com.bbit.silk.utils.global; + +import com.bbit.silk.utils.MMKVUtil; + +/** + * @Description MMKV + * @Author DuanKaiji + * @CreateTime 2024年03月27日 13:48 + */ +public class Global { + /** + * Token + */ + public static final String TOKEN = "TOKEN"; + /** + * 公司ID + */ + public static final String COMPANY_ID = "COMPANY_ID"; + public static final String REG_NAME = "REG_NAME"; + public static final String REG_TEL = "REG_TEL"; + public static final String TOKEN_TIME = "TOKEN_TIME"; + /** + * 所属部门ID + */ + public static final String DEP_SYS_ID = "DEP_SYS_ID"; + + public static String getDepSysId() { + return MMKVUtil.get(DEP_SYS_ID, "——"); + } + + public static boolean isTokenAvailable() { + //10分钟后都没过期 + return System.currentTimeMillis() < MMKVUtil.get(TOKEN_TIME, 0L) - 10 * 60 * 1000; + } + + public static String getRegName() { + return MMKVUtil.get(REG_NAME, "——"); + } + + public static String getRegTel() { + return MMKVUtil.get(REG_TEL, "——"); + } + + /** + * 用户ID + */ + public static final String USER_ID = "USER_ID"; + /** + * 用户名 + */ + public static final String USER_NAME = "USER_NAME"; + /** + * 用户账号 + */ + public static final String USER_ACCOUNT = "USER_ACCOUNT"; + /** + * 密码 + */ + public static final String PASSWORD = "PASSWORD"; + /** + * 设备码 + */ + public static final String DEVICE_ID = "DEVICE_ID"; + + /** + * 默认单位 + */ + public static final String UNIT = "UNIT"; + /** + * 公司名称 + */ + public static final String COMPANY_NAME = "COMPANY_NAME"; + /** + * 茧站名称 + */ + public static final String STATION_NAME = "STATION_NAME"; + + public static String getStationName() { + return MMKVUtil.get(STATION_NAME, "——"); + } + + public static String getDeviceId() { + return MMKVUtil.get(DEVICE_ID, "——"); + } + + public static String getUnit() { + return MMKVUtil.get(UNIT, SpinnerList.UNIT[0]); + } + + public static String getCompanyId() { + return MMKVUtil.get(COMPANY_ID, "未授权").toUpperCase(); + } + + public static String getUserName() { + return MMKVUtil.get(USER_NAME, "——"); + } + + public static String getUserAccount() { + return MMKVUtil.get(USER_ACCOUNT, ""); + } + + public static String getPassword() { + return MMKVUtil.get(PASSWORD, null); + } + + public static String getUserId() { + return MMKVUtil.get(USER_ID, "——"); + } + + public static String getCompanyName() { + return MMKVUtil.get(COMPANY_NAME, "——"); + } + + /** + * 单位 + * 用于换算 + */ + public static int getUnitInt() { + if (SpinnerList.UNIT[0].equals(getUnit())) { + return 1; + } else { + return 2; + } + } +} diff --git a/app/src/main/java/com/bbit/silk/utils/global/SpinnerList.java b/app/src/main/java/com/bbit/silk/utils/global/SpinnerList.java new file mode 100644 index 0000000..f20267b --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/global/SpinnerList.java @@ -0,0 +1,11 @@ +package com.bbit.silk.utils.global; + +/** + * 通用数组 + */ +public class SpinnerList { + /** + * + */ + public static String[] UNIT = {"公斤", "市斤"}; +} diff --git a/app/src/main/java/com/bbit/silk/utils/log/CrashHandlerUtil.java b/app/src/main/java/com/bbit/silk/utils/log/CrashHandlerUtil.java new file mode 100644 index 0000000..9a089c1 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/log/CrashHandlerUtil.java @@ -0,0 +1,61 @@ +package com.bbit.silk.utils.log; + + +import android.content.Context; +import android.content.Intent; + +public class CrashHandlerUtil implements Thread.UncaughtExceptionHandler { + /** + * 饿汉式单例模式 + */ + private static CrashHandlerUtil crashHandlerUtil = new CrashHandlerUtil(); + private Thread.UncaughtExceptionHandler mDefaultCaughtExceptionHandler; + private Context mContext; + + private CrashHandlerUtil() { + // 私有构造函数,确保单例模式 + } + + public static CrashHandlerUtil getInstance() { + return crashHandlerUtil; + } + + public void init(Context context) { + mContext = context; + mDefaultCaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(this); + } + + @Override + public void uncaughtException(Thread thread, Throwable ex) { + ex.printStackTrace(); + MyLog.appError("软件已崩溃,重启应用:" + getFormattedException(ex)); + Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName()); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + mContext.startActivity(intent); + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(0); + } + + /** + * 格式化异常信息的方法 + */ + public String getFormattedException(Throwable throwable) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("异常详情:\n") + .append("异常类型:").append(throwable.getClass().getName()).append("\n") + .append("异常消息:").append(throwable.getMessage()).append("\n"); + StackTraceElement[] stackTrace = throwable.getStackTrace(); + if (stackTrace != null && stackTrace.length > 0) { + stringBuilder.append("异常位置:").append(stackTrace[0].toString()).append("\n"); + } + + stringBuilder.append("完整堆栈跟踪:\n"); + for (StackTraceElement element : stackTrace) { + stringBuilder.append("\t").append(element.toString()).append("\n"); + } + + return stringBuilder.toString(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/utils/log/MyLog.java b/app/src/main/java/com/bbit/silk/utils/log/MyLog.java new file mode 100644 index 0000000..8a4fb90 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/log/MyLog.java @@ -0,0 +1,137 @@ +package com.bbit.silk.utils.log; + + +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import timber.log.Timber; + +public class MyLog extends Timber.Tree { + public static final String TAG_ERROR = "Error"; + /** + * 测试类 + */ + public static final String TAG_TEST = "调试"; + /** + * 预警类 + */ + public static final String TAG_WARNING = "预警"; + + /** + * 传感器类 + */ + public static final String TAG_SENSOR = "传感器"; + + /** + * 控制器类 + */ + public static final String TAG_CONTROLLER = "控制器"; + + /** + * 网络类 + */ + public static final String TAG_NETWORK = "网络"; + + /** + * 系统类 + */ + public static final String TAG_APP = "系统"; + + /** + * 远程控制类 + */ + public static final String TAG_REMOTE = "远程控制"; + + /** + * 自动控制类 + */ + public static final String TAG_AUTO = "自动控制"; + /** + * 人脸识别类 + */ + public static final String TAG_FACE = "人脸识别"; + + public static List getUserQueryTag() { + List tags = new ArrayList<>(); + Collections.addAll(tags, TAG_APP, TAG_REMOTE, TAG_CONTROLLER, TAG_WARNING,TAG_SENSOR, TAG_NETWORK, TAG_AUTO); + return tags; + } + + public static void test(String msg) { + Timber.tag(TAG_TEST).i(msg); + } + + public static void auto(String msg) { + Timber.tag(TAG_AUTO).i(msg); + } + + public static void autoError(String msg) { + Timber.tag(TAG_AUTO + TAG_ERROR).e(msg); + } + + public static void warning(String msg) { + Timber.tag(TAG_WARNING).i(msg); + } + + public static void warningError(String msg) { + Timber.tag(TAG_WARNING + TAG_ERROR).e(msg); + } + + public static void sensor(String msg) { + Timber.tag(TAG_SENSOR).i(msg); + } + + public static void sensorError(String msg) { + Timber.tag(TAG_SENSOR + TAG_ERROR).e(msg); + } + + public static void controller(String msg) { + Timber.tag(TAG_CONTROLLER).i(msg); + } + + public static void controllerError(String msg) { + Timber.tag(TAG_CONTROLLER + TAG_ERROR).e(msg); + } + + public static void network(String msg) { + Timber.tag(TAG_NETWORK).i(msg); + } + + public static void networkError(String msg) { + Timber.tag(TAG_NETWORK + TAG_ERROR).e(msg); + } + + public static void app(String msg) { + Timber.tag(TAG_APP).i(msg); + } + + public static void appError(String msg) { + Timber.tag(TAG_APP + TAG_ERROR).e(msg); + } + + public static void remote(String msg) { + Timber.tag(TAG_REMOTE).i(msg); + } + + public static void remoteError(String msg) { + Timber.tag(TAG_REMOTE + TAG_ERROR).e(msg); + } + + public static void face(String msg) { + Timber.tag(TAG_FACE).i(msg); + } + + public static void faceError(String msg) { + Timber.tag(TAG_FACE + TAG_ERROR).e(msg); + } + + @Override + protected void log(int priority, String tag, String message, Throwable t) { + //输出日志到控制台 + new Thread(() -> Log.println(priority, tag, message)).start(); + } + +} diff --git a/app/src/main/java/com/bbit/silk/utils/network/Url.java b/app/src/main/java/com/bbit/silk/utils/network/Url.java new file mode 100644 index 0000000..7d657bb --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/network/Url.java @@ -0,0 +1,97 @@ +package com.bbit.silk.utils.network; + +public class Url { + /** + * Environment 当前环境 true 生产环境 false 测试环境 + */ +// private static final boolean userProduct = true; + private static final boolean userProduct = false; + private static String baseUrls; + + public static void initUrl() { + if (userProduct) { + // 生产环境 + baseUrls = "https://f8.api.dev.bbitcn.cn/"; + } else { + // 测试环境 + baseUrls = "http://f8.api.dev.bbitcn.cn:9999/"; + } + login = baseUrls + "api/CBMSAccount/LoginJwtAndValidHardware"; + getNewVersion = baseUrls + "api/app/App.ZHCS.GetNewVersion"; + auth = baseUrls + "api/client/Authorize.AddInfo"; + isAuth = baseUrls + "api/client/Authorize.IsAuthorize"; + getUserInfo = baseUrls + "api/CBMSAccount/GetLoginInfoByJwt"; + getPriceOfToday = baseUrls + "api/app/App.ZHCS.Common.GetTodayPrice"; + queryList = baseUrls + "api/app/App.ZHCS.Bangdan.GetViewList"; + queryStatistics = baseUrls + "api/app/App.ZHCS.Bangdan.GetStatistic"; + getAllType = baseUrls + "api/app/App.ZHCS.GetAllSgType"; + toConvert = baseUrls + "api/app/App.ZHCS.Bangdan.ChangeSgType"; + tareSubmit = baseUrls +"api/app/App.ZHCS.Bangdan.KoupiDingjia"; + weather = baseUrls +"api/Weather/GetWeatherInfoForecasts"; + getAboutInfo = baseUrls + "api/app/App.ZHCS.Common.GetAboutInfo"; + checkAuth = baseUrls + "api/client/Authorize.IsAuthorize"; + configOrCancel = baseUrls + "api/ShouGou/ChengZhong.UpdateBillState"; + } + + /** + * 登录 + * 获取Token + */ + public static String login; + /** + * 获取最新版本 + */ + public static String getNewVersion; + /** + * 进行授权 + */ + public static String auth; + /** + * 判断是否授权 + */ + public static String isAuth; + /** + * 获取用户信息 + */ + public static String getUserInfo; + /** + * 获取今日价格 + */ + public static String getPriceOfToday; + /** + * 磅单查询 扣皮定价 茧别转换 + */ + public static String queryList; + /** + * 收购统计 + */ + public static String queryStatistics; + /** + * 查询所有收购类型 + */ + public static String getAllType; + /** + * 茧别转换 + */ + public static String toConvert; + /** + * 扣皮保存 + */ + public static String tareSubmit; + /** + * 天气 + */ + public static String weather; + /** + * 关于信息 + */ + public static String getAboutInfo; + /** + * 检查授权状态 + */ + public static String checkAuth; + /** + * 弃售/确认售 + */ + public static String configOrCancel; +} diff --git a/app/src/main/java/com/bbit/silk/utils/network/XHttpManager.java b/app/src/main/java/com/bbit/silk/utils/network/XHttpManager.java new file mode 100644 index 0000000..300832f --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/network/XHttpManager.java @@ -0,0 +1,61 @@ +package com.bbit.silk.utils.network; + +import com.bbit.silk.utils.MMKVUtil; +import com.bbit.silk.utils.global.Global; + +import org.xutils.http.RequestParams; + +/** + * @Author:BinJianXin + * @Date:2022/5/30/9:34 + * @Declaration: + */ +public class XHttpManager { + private static XHttpManager xHttpManager; + + public static XHttpManager getInstance() { + if (xHttpManager == null) { + synchronized (XHttpManager.class) { + if (xHttpManager == null) { + xHttpManager = new XHttpManager(); + } + } + } + return xHttpManager; + } + + /** + * 获得网络请求头 + * + * @param url 地址 + */ + public RequestParams getRequestParams(String url) { + return getRequestParams(url, true, false, 0, 0); + } + + /** + * 获得网络请求头 + * + * @param url 地址 + * @param needToken 是否需要token + */ + public RequestParams getRequestParams(String url, boolean needToken) { + return getRequestParams(url, needToken, false, 0, 0); + } + public RequestParams getRequestParams(String url, boolean needToken, boolean needPage, int page, int limit) { + RequestParams params = new RequestParams(url); + params.setReadTimeout(10000); + params.setConnectTimeout(10000); + params.addHeader("Content-Type", "application/json,charset=UTF-8"); + params.setUseCookie(false); + params.setAsJsonContent(true); + if (needToken) { + params.addHeader("Authorization", MMKVUtil.get(Global.TOKEN)); + } + if (needPage) { + //NeedPage:是否需要分页,Page:第几页,Limit:每页数目,OrderBy:排序 + params.addHeader("Page-Info", "{\"NeedPage\":true,\"Page\":" + page + ",\"Limit\":" + limit + ",\"OrderBy\":\"\"}"); + } + return params; + } +} diff --git a/app/src/main/java/com/bbit/silk/utils/network/XHttpShorthand.java b/app/src/main/java/com/bbit/silk/utils/network/XHttpShorthand.java new file mode 100644 index 0000000..24e0a32 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/utils/network/XHttpShorthand.java @@ -0,0 +1,125 @@ +package com.bbit.silk.utils.network; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.bbit.silk.model.CommonResponse; +import com.bbit.silk.utils.log.MyLog; +import com.blankj.utilcode.util.GsonUtils; + +import org.json.JSONException; +import org.xutils.common.Callback; + +import java.lang.reflect.ParameterizedType; +import java.net.UnknownHostException; + +/** + * @Author:BinJianXin + * @Date:2022/5/30/9:49 + * @Declaration:用于减少逻辑界面xhttp需要实现的方法数 + */ +public abstract class XHttpShorthand implements Callback.CommonCallback { + + public abstract void success(T result) throws JSONException; + + private Class clazz; + + public XHttpShorthand() { + try { + ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); + clazz = (Class) genericSuperclass.getActualTypeArguments()[0]; + } catch (Exception e) { + e.printStackTrace(); + } + } + + public abstract void error(Throwable e); + + @Override + public void onSuccess(String result) { + MyLog.network("网络请求成功:" + result); + Message message = new Message(); + try { + CommonResponse temp = GsonUtils.fromJson(result, CommonResponse.class); + MyLog.network("已转为通用请求内容"); + if (temp != null) { +// MyLog.network("Code == 200"); + message.what = 0; + message.obj = GsonUtils.fromJson(result, clazz); + } else { +// MyLog.network("Code != 200"); + message.what = 2; + message.obj = temp; + } + } catch (Exception e) { + message.what = 1; + message.obj = e; + } + handler.sendMessage(message); + } + + public void onSuccessError(CommonResponse data) { + + } + + @Override + public void onError(Throwable ex, boolean isOnCallback) { + MyLog.networkError("网络请求失败:错误消息:" + ex.getMessage() + "\t本地化消息:" + ex.getLocalizedMessage() + "\t原因:" + ex.getCause()); + if(ex instanceof UnknownHostException){ + //修改ex.getMessage()为"网络连接失败,请检查网络连接" 友好型提示 + ex = new Throwable("网络连接失败,请检查网络连接"); + } +// if (401 == ((HttpException) ex).getCode()) { +// MyLog.networkError("未授权"); +// //跳转到登录界面 +// Activity topActivity = ActivityUtils.getTopActivity(); +// ActivityUtils.startActivities(new Intent[]{new Intent(topActivity, LoginActivity.class)}); +// topActivity.finish(); +// } else { + Message message = new Message(); + message.what = 1; + message.obj = ex; + handler.sendMessage(message); +// } + } + + @Override + public void onCancelled(CancelledException cex) { + MyLog.network("网络请求取消" + cex.getMessage()); + } + + @Override + public void onFinished() { + Message message = new Message(); + message.what = 3; + handler.sendMessage(message); + } + + public void myFinish() { + MyLog.network("网络请求完成"); + } + + /** + * 转回到主线程 + */ + public Handler handler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(@androidx.annotation.NonNull Message msg) { + super.handleMessage(msg); + try { + if (msg.what == 0) { + success((T) msg.obj); + } else if (msg.what == 1) { + error((Throwable) msg.obj); + } else if (msg.what == 2) { + onSuccessError((CommonResponse) msg.obj); + } else if (msg.what == 3) { + myFinish(); + } + } catch (Exception e) { + MyLog.networkError("网络请求错误:" + e.getMessage()); + } + } + }; +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/viewmodel/AboutViewModel.kt b/app/src/main/java/com/bbit/silk/viewmodel/AboutViewModel.kt new file mode 100644 index 0000000..d9e0fa9 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/viewmodel/AboutViewModel.kt @@ -0,0 +1,44 @@ +package com.bbit.silk.viewmodel; + +import BaseViewModel +import com.bbit.silk.model.About +import com.bbit.silk.utils.network.Url +import com.bbit.silk.utils.network.XHttpManager +import com.bbit.silk.utils.network.XHttpShorthand +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import org.xutils.x + +class AboutViewModel : BaseViewModel() { + val _aboutInfo = MutableStateFlow(About.Data()) + val aboutInfo: StateFlow = _aboutInfo.asStateFlow() + + init { + getAboutInfo() + } + + fun getAboutInfo() { + showLoadingDialog("正在加载信息") + val params = XHttpManager.getInstance().getRequestParams(Url.getAboutInfo, false) + x.http().get(params, object : XHttpShorthand() { + override fun success(model: About) { + if (model.result) { + _aboutInfo.update { model.data } + } else { + showTipsDialog(model.msg) + } + } + + override fun error(e: Throwable) { + showTipsDialog("关于信息获取失败:" + e.message) + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } +} diff --git a/app/src/main/java/com/bbit/silk/viewmodel/AuthViewModel.kt b/app/src/main/java/com/bbit/silk/viewmodel/AuthViewModel.kt new file mode 100644 index 0000000..ce0df27 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/viewmodel/AuthViewModel.kt @@ -0,0 +1,137 @@ +package com.bbit.silk.viewmodel; + +import BaseViewModel +import androidx.lifecycle.MutableLiveData +import com.bbit.silk.model.Auth +import com.bbit.silk.model.CheckAuth +import com.bbit.silk.ui.view.TipsDialogData +import com.bbit.silk.utils.MMKVUtil +import com.bbit.silk.utils.global.Global +import com.bbit.silk.utils.log.MyLog +import com.bbit.silk.utils.network.Url +import com.bbit.silk.utils.network.XHttpManager +import com.bbit.silk.utils.network.XHttpShorthand +import com.blankj.utilcode.util.EncryptUtils +import com.blankj.utilcode.util.StringUtils +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import org.xutils.x + +class AuthViewModel : BaseViewModel() { + /** + * 1:已授权 2:待授权 0:未授权 + */ + private val _notice = MutableStateFlow(0) + val notice: StateFlow = _notice.asStateFlow() + + init { + if ("未授权" != Global.getCompanyId()) { + checkAuth() + } + } + + /** + * 检查授权状态 + */ + fun checkAuth() { + showLoadingDialog("正在检查授权状态") + val params = XHttpManager.getInstance().getRequestParams(Url.checkAuth, false) + params.addParameter("TenantCode", Global.getCompanyId()) + params.addParameter("HardwareId", Global.getDeviceId()) + x.http().get(params, object : XHttpShorthand() { + override fun success(model: CheckAuth) { + if (model.result) { + if (model.data.flag == 1) { + MMKVUtil.put(Global.COMPANY_ID, model.data.tenantCode) + MMKVUtil.put(Global.REG_NAME, model.data.applicant) + MMKVUtil.put(Global.REG_TEL, model.data.phone) + MyLog.app("状态为:已授权") + _notice.update { 1 } + } else { + MyLog.app("状态为:待授权") + _notice.update { 2 } + } + } else { + MyLog.appError("授权失败") + showTipsDialog(model.msg) + } + } + + override fun error(e: Throwable) { + MyLog.appError("网络错误授权失败") + _notice.update { 0 } + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + + /** + * 进行授权 + * + * @param id 公司ID + * @param name 授权人名 + * @param tel 授权人电话 + * @param pwd 授权密码 + */ + fun auth(id: String, name: String, tel: String, pwd: String?) { + if (StringUtils.isEmpty(id) || StringUtils.isEmpty(name) || StringUtils.isEmpty(tel)) { + showTipsDialog("请先完善信息") + return + } + showLoadingDialog("正在授权中...") + val params = XHttpManager.getInstance().getRequestParams(Url.auth, false) + pwd?.let { + // 将 pwd 进行 MD5 加密 + var encryptedPwd = EncryptUtils.encryptMD5ToString(it.toByteArray()) + // 并全部大写 + encryptedPwd = encryptedPwd.uppercase() + params.addQueryStringParameter("pwd", encryptedPwd) + } + params.addParameter("TenantCode", id) + params.addParameter("HardwareId", Global.getDeviceId()) + params.addParameter("Applicant", name) + params.addParameter("Job", "") + params.addParameter("Memo", "") + params.addParameter("ClientType", 2) + params.addParameter("Phone", tel) + x.http().put(params, object : XHttpShorthand() { + override fun success(model: Auth) { + if (model.result) { + if (model.data.flag == 1) { + MMKVUtil.put(Global.COMPANY_ID, model.data.tenantCode) + MMKVUtil.put(Global.REG_NAME, model.data.applicant) + MMKVUtil.put(Global.REG_TEL, model.data.phone) + MyLog.app("状态为:已授权") + _notice.update { 1 } + } else { + MMKVUtil.put(Global.COMPANY_ID, id) + MMKVUtil.put(Global.REG_NAME, name) + MMKVUtil.put(Global.REG_TEL, tel) + MyLog.app("状态为:待授权") + _notice.update { 2 } + } + } else { + MyLog.appError("授权失败") + showTipsDialog(model.msg) + } + } + + override fun error(e: Throwable) { + MyLog.appError("网络错误授权失败") + _notice.update { 0 } + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + +} diff --git a/app/src/main/java/com/bbit/silk/viewmodel/DataViewModel.kt b/app/src/main/java/com/bbit/silk/viewmodel/DataViewModel.kt new file mode 100644 index 0000000..ad80b0a --- /dev/null +++ b/app/src/main/java/com/bbit/silk/viewmodel/DataViewModel.kt @@ -0,0 +1,294 @@ +package com.bbit.silk.viewmodel + +import BaseViewModel +import androidx.navigation.NavController +import com.bbit.silk.model.AllType +import com.bbit.silk.model.CommonResponse +import com.bbit.silk.model.Login +import com.bbit.silk.model.QueryList +import com.bbit.silk.model.Statistics +import com.bbit.silk.model.ToConvert +import com.bbit.silk.model.ToTareSubmit +import com.bbit.silk.utils.database.AllTypeDataBase +import com.bbit.silk.utils.database.PriceDataBase +import com.bbit.silk.utils.database.TareDataBase +import com.bbit.silk.utils.global.Global +import com.bbit.silk.utils.log.MyLog +import com.bbit.silk.utils.network.Url +import com.bbit.silk.utils.network.XHttpManager +import com.bbit.silk.utils.network.XHttpShorthand +import com.blankj.utilcode.util.TimeUtils +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.suspendCancellableCoroutine +import org.xutils.x + +/** + * + * @Description TODO + * @Author DuanKaiji + * @CreateTime 2024年05月09日 17:07:42 + */ +class DataViewModel : BaseViewModel() { + + //收购统计信息 + private val _isFinish = MutableStateFlow(false) + val isFinish = _isFinish.asStateFlow() + + //收购统计信息 + private val _isLoading = MutableStateFlow(false) + val isLoading = _isLoading.asStateFlow() + + //收购统计信息 + private val _totalInfo = MutableStateFlow(Statistics.Data()) + val totalInfo = _totalInfo.asStateFlow() + + //常规查询 + private val _queryList = MutableStateFlow(listOf()) + val queryList = _queryList.asStateFlow() + + /** + * 收购统计 + */ + fun getTotalInfo(startDate: String, endDate: String) { + //判断时间区间是否合理 + if (TimeUtils.string2Date(startDate, "yyyy-MM-dd").time > + TimeUtils.string2Date(endDate, "yyyy-MM-dd").time + ) { + showTipsDialog("开始时间不能大于结束时间") + return + } + showLoadingDialog("正在查询统计信息") + val params = XHttpManager.getInstance().getRequestParams(Url.queryStatistics) + params.addParameter("dtstart", startDate) + params.addParameter("dtend", endDate) + params.addParameter("depsysid", Global.getDepSysId()) + x.http().post(params, object : XHttpShorthand() { + override fun success(model: Statistics) { + // 如果查询成功 + if (model.result) { + MyLog.app("查询成功") + _totalInfo.update { model.data } + } else { + showTipsDialog("查询失败" + model.msg) + MyLog.appError("查询失败" + model.msg) + } + } + + override fun error(e: Throwable) { + // 处理错误 + showTipsDialog("查询失败" + e.message) + MyLog.appError("查询失败") + } + + override fun myFinish() { + super.myFinish() + // 隐藏加载对话框 + hideLoadingDialog() + } + }) + } + + /** + * 常规查询 + */ + fun queryData( + type: Int, + startDate: String, + endDate: String, + key: String = "", // 默认为空 + page: Int = 1, // 默认第一页 + ){ + val lastSize = queryList.value.size + //判断时间区间是否合理 + if (TimeUtils.string2Date(startDate, "yyyy-MM-dd").time > + TimeUtils.string2Date(endDate, "yyyy-MM-dd").time + ) { + showTipsDialog("开始时间不能大于结束时间") + return + } + val limit = 5// 默认每页5条 + val params = XHttpManager.getInstance() + .getRequestParams(Url.queryList, true, true, 1, page * limit) + _isLoading.update { true } + params.addParameter("type", type) + params.addParameter("dtstart", startDate) + params.addParameter("dtend", endDate) + params.addParameter("like", key) + params.addParameter("depsysid", Global.getDepSysId()) + x.http().post(params, object : XHttpShorthand() { + override fun success(model: QueryList) { + if (model.result) { + MyLog.app("查询成功") + _queryList.update { model.data } + _isFinish.update { model.data.size == lastSize } + } else { + showTipsDialog("查询失败" + model.msg) + MyLog.appError("查询失败") + } + } + + override fun error(e: Throwable) { + MyLog.appError("查询失败") + showTipsDialog("查询失败" + e.message) + } + + override fun myFinish() { + super.myFinish() + _isLoading.update { false } + } + }) + } + + /** + * 查询所有收购类型 + */ + fun refreshAllType() { + showLoadingDialog("正在获取所有茧别") + val params = XHttpManager.getInstance().getRequestParams(Url.getAllType) + x.http().get(params, object : XHttpShorthand() { + override fun success(model: AllType) { + if (model.result) { + AllTypeDataBase.setAllType(model.data) + } else { + showTipsDialog(model.msg) + } + } + + override fun error(e: Throwable) { + showTipsDialog("获取茧别失败:" + e.message) + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + + /** + * 茧别转换 + */ + fun convert( + navController: NavController, + convert: ToConvert + ) { + convert.items = convert.items.filterNot { it.newsgtypesysid.isEmpty() } + convert.items.map { item -> + item.oldsgtypesysid = AllTypeDataBase.getSysIdByName(item.oldsgtypesysid) + item.newsgtypesysid = AllTypeDataBase.getSysIdByName(item.newsgtypesysid) + } + showLoadingDialog("正在转换中...") + val params = XHttpManager.getInstance().getRequestParams(Url.toConvert) + params.addParameter("czsysid", convert.czsysid) + params.addParameter("items", convert.items) + x.http().post(params, object : XHttpShorthand() { + override fun success(model: CommonResponse) { + if (model.result) { + navController.popBackStack() + } else { + showTipsDialog(model.msg) + } + } + + override fun error(e: Throwable) { + showTipsDialog("转换失败:" + e.message) + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + + /** + * 扣皮定价 + */ + fun tare( + oldData: QueryList.Data, + navController: NavController, + data: ToTareSubmit + ) { + data.items.forEach { + val name = AllTypeDataBase.getNameBySysId(it.sgtypesysid) + val minMaxPrice: DoubleArray = PriceDataBase.getCatchById(name) + if (it.pizhong <= 0.0) { + showTipsDialog("${name} 皮重数据异常,请检查") + return + } + if (it.price <= 0.0) { + showTipsDialog("${name} 单价数据异常,请检查") + return + } + if (it.price < minMaxPrice[0] || it.price > minMaxPrice[1]) { + showTipsDialog("${name}的今日参考价格为¥${minMaxPrice[0]}~¥${minMaxPrice[1]} ,请重新定价") + return + } + oldData.items.forEach { dataIt -> + if (dataIt.sgTypeSysid == it.sgtypesysid + && (it.pizhong + it.kouzhong > dataIt.maozhong) + ) { + showTipsDialog("$name 净重数据异常,请检查") + return + } + } + } + showLoadingDialog("正在提交中") + val params = XHttpManager.getInstance().getRequestParams(Url.tareSubmit) + params.addParameter("czsysid", data.czsysid) + params.addParameter("items", data.items) + x.http().post(params, object : XHttpShorthand() { + override fun success(model: CommonResponse) { + if (model.result) { + navController.popBackStack() + TareDataBase.removeCatchById(oldData) + } else { + showTipsDialog(model.msg) + } + } + + override fun error(e: Throwable) { + showTipsDialog("提交失败:" + e.message) + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + + /** + * 弃售/确认销售 + * + * @param type -1 弃售 2 确认销售 + * @param id 称重sysid + */ + fun cancelOrConfirm(navController: NavController? = null, id: String, type: Int) { + showLoadingDialog("正在提交弃售中") + val params = XHttpManager.getInstance().getRequestParams(Url.configOrCancel) + params.addQueryStringParameter("sgBillstate", type) + params.addQueryStringParameter("czsysid", id) + x.http().put(params, object : XHttpShorthand() { + override fun success(model: CommonResponse) { + if (model.result) { + navController?.popBackStack() + } else { + showTipsDialog(model.msg) + } + } + + override fun error(e: Throwable) { + showTipsDialog("弃售失败:" + e.message) + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bbit/silk/viewmodel/LoginViewModel.kt b/app/src/main/java/com/bbit/silk/viewmodel/LoginViewModel.kt new file mode 100644 index 0000000..8ca8901 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/viewmodel/LoginViewModel.kt @@ -0,0 +1,100 @@ +package com.bbit.silk.viewmodel; + +import BaseViewModel +import android.content.Context +import androidx.lifecycle.MutableLiveData +import com.bbit.silk.model.Login +import com.bbit.silk.utils.MMKVUtil +import com.bbit.silk.utils.global.Global +import com.bbit.silk.utils.log.MyLog +import com.bbit.silk.utils.network.Url +import com.bbit.silk.utils.network.XHttpManager +import com.bbit.silk.utils.network.XHttpShorthand +import com.blankj.utilcode.util.EncryptUtils +import com.hjq.permissions.OnPermissionCallback +import com.hjq.permissions.Permission +import com.hjq.permissions.XXPermissions +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import org.xutils.x + +class LoginViewModel : BaseViewModel() { + private val _getInMainScreen = MutableStateFlow(false) + val getInMainScreen = _getInMainScreen.asStateFlow() + fun resetGetInMainScreen() { + _getInMainScreen.value = false + } + + + /** + * 登录 + * + * @param account 账号 + * @param password 密码 + */ + fun login(account: String, password: String) { + if (account.isEmpty() || password.isEmpty()) { + showTipsDialog("账号密码不能为空") + return + } + showLoadingDialog("正在登录中...") + val params = XHttpManager.getInstance().getRequestParams(Url.login, false) + params.addParameter("Platform", "1") + params.addParameter("HardwareId", Global.getDeviceId()) + params.addParameter("TenantCode", Global.getCompanyId()) + params.addParameter("Account", account) + params.addParameter("Password", EncryptUtils.encryptMD5ToString(password.toByteArray())) + x.http().post(params, object : XHttpShorthand() { + override fun success(model: Login) { + MyLog.app("登录成功") + if (model.result) { + MMKVUtil.put(Global.USER_ACCOUNT, account) + MMKVUtil.put(Global.PASSWORD, password) + MMKVUtil.put(Global.TOKEN, "${model.data.tokenType} ${model.data.accessToken}") + _getInMainScreen.update { true } + } else { + showTipsDialog("登录失败:" + model.msg) + } + } + + override fun error(e: Throwable) { + showTipsDialog("登录失败:" + e.message) + MyLog.appError("Token获取失败: ${e.message}") + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + + /** + * 检查与请求权限 + */ + fun checkPermission(context: Context) { + XXPermissions.with(context) + .permission(Permission.WRITE_EXTERNAL_STORAGE) + .permission(Permission.READ_PHONE_STATE) + .permission(Permission.REQUEST_INSTALL_PACKAGES) + .request(object : OnPermissionCallback { + override fun onGranted(permissions: List, allGranted: Boolean) { + if (!allGranted) { + MyLog.appError("获取部分权限成功,但部分权限未正常授予") + XXPermissions.startPermissionActivity(context, permissions) + } + } + + override fun onDenied(permissions: List, doNotAskAgain: Boolean) { + if (doNotAskAgain) { + MyLog.app("被永久拒绝授权,需手动授予权限") + // 如果是被永久拒绝就跳转到应用权限系统设置页面 + XXPermissions.startPermissionActivity(context, permissions) + } else { + MyLog.appError("权限请求失败") + } + } + }) + } +} diff --git a/app/src/main/java/com/bbit/silk/viewmodel/MainViewModel.kt b/app/src/main/java/com/bbit/silk/viewmodel/MainViewModel.kt new file mode 100644 index 0000000..cae2457 --- /dev/null +++ b/app/src/main/java/com/bbit/silk/viewmodel/MainViewModel.kt @@ -0,0 +1,132 @@ +package com.bbit.silk.viewmodel; + +import BaseViewModel +import com.bbit.silk.model.TodayPrice +import com.bbit.silk.model.UserInfo +import com.bbit.silk.model.Weather +import com.bbit.silk.utils.MMKVUtil +import com.bbit.silk.utils.MyUtil +import com.bbit.silk.utils.database.PriceDataBase +import com.bbit.silk.utils.global.Global +import com.bbit.silk.utils.log.MyLog +import com.bbit.silk.utils.network.Url +import com.bbit.silk.utils.network.XHttpManager +import com.bbit.silk.utils.network.XHttpShorthand +import com.blankj.utilcode.util.StringUtils +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import org.xutils.x + +class MainViewModel : BaseViewModel() { + + //用户信息 + private val _userInfo = MutableStateFlow(UserInfo.Data()) + val userInfo: StateFlow = _userInfo.asStateFlow() + //是否进入登录界面 + private val _getInLoginScreen = MutableStateFlow(false) + val getInLoginScreen: StateFlow = _getInLoginScreen.asStateFlow() + //天气信息 + private val _weather = MutableStateFlow(Weather.Data()) + val weather: StateFlow = _weather.asStateFlow() + //今日价格信息 + private val _price = MutableStateFlow(TodayPrice.Data()) + val price: StateFlow = _price.asStateFlow() + + var hasRefreshed: Boolean = false + + /** + * 获取信息 + */ + fun refreshInfo() { + if (hasRefreshed) { + return + } else { + //刷新用户信息 + if (StringUtils.isEmpty(MMKVUtil.get(Global.TOKEN))) { + //之前没登陆过 -> 跳转到登录界面 + _getInLoginScreen.update { true } + } else { + //之前登陆过 -> 静默登录(后获取用户信息) + MyUtil.login { + hasRefreshed = true + refreshUserInfo() + refreshWeather() + refreshPriceOfToday() + } + } + } + } + + /** + * 获取用户信息 + */ + private fun refreshUserInfo() { + val params = XHttpManager.getInstance().getRequestParams(Url.getUserInfo) + x.http().get(params, object : XHttpShorthand() { + override fun success(model: UserInfo) { + MyLog.app("用户信息获取成功") + _userInfo.update { model.data } + MMKVUtil.put(Global.USER_NAME, model.data.userName) + MMKVUtil.put(Global.USER_ID, model.data.userSysID) + MMKVUtil.put(Global.COMPANY_NAME, model.data.tenantName) + MMKVUtil.put(Global.STATION_NAME, model.data.depName) + MMKVUtil.put(Global.DEP_SYS_ID, model.data.depSysid) + } + + override fun error(e: Throwable) { + MyLog.appError("用户信息获取失败") + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + /** + * 获取天气 + */ + fun refreshWeather() { + val params = XHttpManager.getInstance().getRequestParams(Url.weather) + x.http().get(params, object : XHttpShorthand() { + override fun success(model: Weather) { + _weather.update { model.data } + } + + override fun error(e: Throwable) { + MyLog.appError("今日价格获取失败") + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + /** + * 获取今日价格 + */ + fun refreshPriceOfToday() { + showLoadingDialog("正在刷新今日价格") + val params = XHttpManager.getInstance().getRequestParams(Url.getPriceOfToday) + x.http().get(params, object : XHttpShorthand() { + override fun success(model: TodayPrice) { + MyLog.app("今日价格获取成功") + PriceDataBase.updateCatch(model.data.items) + _price.update { model.data } + } + + override fun error(e: Throwable) { + MyLog.appError("今日价格获取失败") + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + +} diff --git a/app/src/main/java/com/bbit/silk/viewmodel/UpdateViewModel.kt b/app/src/main/java/com/bbit/silk/viewmodel/UpdateViewModel.kt new file mode 100644 index 0000000..4124bdb --- /dev/null +++ b/app/src/main/java/com/bbit/silk/viewmodel/UpdateViewModel.kt @@ -0,0 +1,148 @@ +package com.bbit.silk.viewmodel; + +import BaseViewModel +import android.content.Intent +import android.os.Build +import android.os.Environment +import android.provider.Settings +import androidx.core.content.FileProvider +import com.bbit.silk.MyApp +import com.bbit.silk.model.Update +import com.bbit.silk.utils.log.MyLog +import com.bbit.silk.utils.network.Url +import com.bbit.silk.utils.network.XHttpManager +import com.bbit.silk.utils.network.XHttpShorthand +import com.blankj.utilcode.util.AppUtils +import com.blankj.utilcode.util.FileUtils +import com.blankj.utilcode.util.StringUtils +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import org.xutils.common.Callback +import org.xutils.http.RequestParams +import org.xutils.x +import java.io.File + +class UpdateViewModel : BaseViewModel() { + + private val _updateInfo = MutableStateFlow(Update.Data()) + val updateInfo: StateFlow = _updateInfo.asStateFlow() + + init { + checkVersion() + } + + /** + * 检查版本 + */ + private fun checkVersion() { + showLoadingDialog("正在检测新版本...") + val params = XHttpManager.getInstance().getRequestParams(Url.getNewVersion, false) + x.http().get(params, object : XHttpShorthand() { + override fun success(model: Update) { + if (model.data != null) { + _updateInfo.update { model.data } + } else if (!StringUtils.isEmpty(model.msg)) { + showTipsDialog(model.msg) + } + } + + override fun error(e: Throwable) { + showTipsDialog("检测失败:" + e.message) + } + + override fun myFinish() { + super.myFinish() + hideLoadingDialog() + } + }) + } + + /** + * 下载APK + */ + fun downFile() { + // 检查 Android 版本,并请求必要的权限 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { + val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) + MyApp.getAppContext().startActivity(intent) + return + } + val fileName = + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + + File.separator + "智慧共育" + updateInfo.value.versionName + ".apk" + // 删除旧文件 + FileUtils.delete(fileName) + val params = RequestParams(updateInfo.value.url) + params.saveFilePath = fileName + params.isAutoRename = true + x.http().get(params, object : Callback.ProgressCallback { + override fun onStarted() { + showProcessDialog(0, "开始下载新版本") + } + + override fun onLoading(total: Long, current: Long, isDownloading: Boolean) { + if (isDownloading) { + val progress = (current * 100 / total).toInt() + showProcessDialog(progress, "新版本已下载$progress%") + } + } + + override fun onSuccess(result: File) { + MyLog.network("下载成功: $result") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + installAPK(fileName) + } else { + AppUtils.installApp(result) + } + } + + override fun onWaiting() { + // 等待下载 + } + + override fun onError(ex: Throwable?, isOnCallback: Boolean) { + MyLog.networkError("下载失败,原因:${ex!!.message}") + showTipsDialog("下载失败,原因:${ex.message}") + } + + override fun onCancelled(cex: Callback.CancelledException) { + // 下载取消 + } + + override fun onFinished() { + hideLoadingDialog() + } + }) + } + + /** + * 安装程序 + * + * @param context 上下文 + * @param filePath 安装的文件路径 + */ + fun installAPK(filePath: String) { + try { + val apkFile = File(filePath) + if (apkFile.exists()) { + val intent = Intent(Intent.ACTION_VIEW) + val apkUri = FileProvider.getUriForFile( + MyApp.getAppContext(), + "${MyApp.getAppContext().packageName}.fileProvider", + apkFile + ) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + intent.setDataAndType(apkUri, "application/vnd.android.package-archive") + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + MyApp.getAppContext().startActivity(intent) + } else { + showTipsDialog("安装包文件不存在") + } + } catch (e: Exception) { + e.printStackTrace() + showTipsDialog("安装失败:${e.message}") + } + } +} diff --git a/app/src/main/java/org/xutils/DbManager.java b/app/src/main/java/org/xutils/DbManager.java new file mode 100644 index 0000000..03c09bf --- /dev/null +++ b/app/src/main/java/org/xutils/DbManager.java @@ -0,0 +1,233 @@ +package org.xutils; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.text.TextUtils; + +import org.xutils.common.util.KeyValue; +import org.xutils.db.Selector; +import org.xutils.db.sqlite.SqlInfo; +import org.xutils.db.sqlite.WhereBuilder; +import org.xutils.db.table.DbModel; +import org.xutils.db.table.TableEntity; +import org.xutils.ex.DbException; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.util.List; + +/** + * 数据库访问接口 + */ +public interface DbManager extends Closeable { + + DaoConfig getDaoConfig(); + + SQLiteDatabase getDatabase(); + + /** + * 保存实体类或实体类的List到数据库, + * 如果该类型的id是自动生成的, 则保存完后会给id赋值. + */ + boolean saveBindingId(Object entity) throws DbException; + + /** + * 保存或更新实体类或实体类的List到数据库, 根据id对应的数据是否存在. + */ + void saveOrUpdate(Object entity) throws DbException; + + /** + * 保存实体类或实体类的List到数据库 + */ + void save(Object entity) throws DbException; + + /** + * 保存或更新实体类或实体类的List到数据库, 根据id和其他唯一索引判断数据是否存在. + */ + void replace(Object entity) throws DbException; + + ///////////// delete + void deleteById(Class entityType, Object idValue) throws DbException; + + void delete(Object entity) throws DbException; + + void delete(Class entityType) throws DbException; + + int delete(Class entityType, WhereBuilder whereBuilder) throws DbException; + + ///////////// update + void update(Object entity, String... updateColumnNames) throws DbException; + + int update(Class entityType, WhereBuilder whereBuilder, KeyValue... nameValuePairs) throws DbException; + + ///////////// find + T findById(Class entityType, Object idValue) throws DbException; + + T findFirst(Class entityType) throws DbException; + + List findAll(Class entityType) throws DbException; + + Selector selector(Class entityType) throws DbException; + + DbModel findDbModelFirst(SqlInfo sqlInfo) throws DbException; + + List findDbModelAll(SqlInfo sqlInfo) throws DbException; + + ///////////// table + + /** + * 获取表信息 + */ + TableEntity getTable(Class entityType) throws DbException; + + /** + * 删除表 + */ + void dropTable(Class entityType) throws DbException; + + /** + * 添加一列, + * 新的entityType中必须定义了这个列的属性. + */ + void addColumn(Class entityType, String column) throws DbException; + + ///////////// db + + /** + * 删除库 + */ + void dropDb() throws DbException; + + /** + * 关闭数据库. + * 同一个库是单实例的, 尽量不要调用这个方法, 会自动释放. + */ + void close() throws IOException; + + ///////////// custom + int executeUpdateDelete(SqlInfo sqlInfo) throws DbException; + + int executeUpdateDelete(String sql) throws DbException; + + void execNonQuery(SqlInfo sqlInfo) throws DbException; + + void execNonQuery(String sql) throws DbException; + + Cursor execQuery(SqlInfo sqlInfo) throws DbException; + + Cursor execQuery(String sql) throws DbException; + + public interface DbOpenListener { + void onDbOpened(DbManager db) throws DbException; + } + + public interface DbUpgradeListener { + void onUpgrade(DbManager db, int oldVersion, int newVersion) throws DbException; + } + + public interface TableCreateListener { + void onTableCreated(DbManager db, TableEntity table); + } + + public static class DaoConfig { + private File dbDir; + private String dbName = "xUtils.db"; // default db name + private int dbVersion = 1; + private boolean allowTransaction = true; + private DbUpgradeListener dbUpgradeListener; + private TableCreateListener tableCreateListener; + private DbOpenListener dbOpenListener; + + public DaoConfig() { + } + + public DaoConfig setDbDir(File dbDir) { + this.dbDir = dbDir; + return this; + } + + public DaoConfig setDbName(String dbName) { + if (!TextUtils.isEmpty(dbName)) { + this.dbName = dbName; + } + return this; + } + + public DaoConfig setDbVersion(int dbVersion) { + this.dbVersion = dbVersion; + return this; + } + + public DaoConfig setAllowTransaction(boolean allowTransaction) { + this.allowTransaction = allowTransaction; + return this; + } + + public DaoConfig setDbOpenListener(DbOpenListener dbOpenListener) { + this.dbOpenListener = dbOpenListener; + return this; + } + + public DaoConfig setDbUpgradeListener(DbUpgradeListener dbUpgradeListener) { + this.dbUpgradeListener = dbUpgradeListener; + return this; + } + + public DaoConfig setTableCreateListener(TableCreateListener tableCreateListener) { + this.tableCreateListener = tableCreateListener; + return this; + } + + public File getDbDir() { + return dbDir; + } + + public String getDbName() { + return dbName; + } + + public int getDbVersion() { + return dbVersion; + } + + public boolean isAllowTransaction() { + return allowTransaction; + } + + public DbOpenListener getDbOpenListener() { + return dbOpenListener; + } + + public DbUpgradeListener getDbUpgradeListener() { + return dbUpgradeListener; + } + + public TableCreateListener getTableCreateListener() { + return tableCreateListener; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DaoConfig daoConfig = (DaoConfig) o; + + if (!dbName.equals(daoConfig.dbName)) return false; + return dbDir == null ? daoConfig.dbDir == null : dbDir.equals(daoConfig.dbDir); + } + + @Override + public int hashCode() { + int result = dbName.hashCode(); + result = 31 * result + (dbDir != null ? dbDir.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return String.valueOf(dbDir) + "/" + dbName; + } + } +} diff --git a/app/src/main/java/org/xutils/HttpManager.java b/app/src/main/java/org/xutils/HttpManager.java new file mode 100644 index 0000000..758447d --- /dev/null +++ b/app/src/main/java/org/xutils/HttpManager.java @@ -0,0 +1,52 @@ +package org.xutils; + +import org.xutils.common.Callback; +import org.xutils.http.HttpMethod; +import org.xutils.http.RequestParams; + +/** + * Created by wyouflf on 15/6/17. + * http请求接口 + */ +public interface HttpManager { + + /** + * 异步GET请求 + */ + Callback.Cancelable get(RequestParams entity, Callback.CommonCallback callback); + + /** + * 异步POST请求 + */ + Callback.Cancelable post(RequestParams entity, Callback.CommonCallback callback); + /** + * 异步POST请求 + */ + Callback.Cancelable put(RequestParams entity, Callback.CommonCallback callback); + + /** + * 异步请求 + */ + Callback.Cancelable request(HttpMethod method, RequestParams entity, Callback.CommonCallback callback); + + + /** + * 同步GET请求 + */ + T getSync(RequestParams entity, Class resultType) throws Throwable; + + /** + * 同步POST请求 + */ + T postSync(RequestParams entity, Class resultType) throws Throwable; + + /** + * 同步请求 + */ + T requestSync(HttpMethod method, RequestParams entity, Class resultType) throws Throwable; + + /** + * 同步请求 + */ + T requestSync(HttpMethod method, RequestParams entity, Callback.TypedCallback callback) throws Throwable; +} diff --git a/app/src/main/java/org/xutils/ImageManager.java b/app/src/main/java/org/xutils/ImageManager.java new file mode 100644 index 0000000..5ec19e8 --- /dev/null +++ b/app/src/main/java/org/xutils/ImageManager.java @@ -0,0 +1,32 @@ +package org.xutils; + +import android.graphics.drawable.Drawable; +import android.widget.ImageView; + +import org.xutils.common.Callback; +import org.xutils.image.ImageOptions; + +import java.io.File; + +/** + * Created by wyouflf on 15/6/17. + * 图片绑定接口 + */ +public interface ImageManager { + + void bind(ImageView view, String url); + + void bind(ImageView view, String url, ImageOptions options); + + void bind(ImageView view, String url, Callback.CommonCallback callback); + + void bind(ImageView view, String url, ImageOptions options, Callback.CommonCallback callback); + + Callback.Cancelable loadDrawable(String url, ImageOptions options, Callback.CommonCallback callback); + + Callback.Cancelable loadFile(String url, ImageOptions options, Callback.CacheCallback callback); + + void clearMemCache(); + + void clearCacheFiles(); +} diff --git a/app/src/main/java/org/xutils/ViewInjector.java b/app/src/main/java/org/xutils/ViewInjector.java new file mode 100644 index 0000000..e2bf92f --- /dev/null +++ b/app/src/main/java/org/xutils/ViewInjector.java @@ -0,0 +1,35 @@ +package org.xutils; + +import android.app.Activity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * Created by wyouflf on 15/10/29. + * view注入接口 + */ +public interface ViewInjector { + + /** + * 注入view + */ + void inject(View view); + + /** + * 注入activity + */ + void inject(Activity activity); + + /** + * 注入view holder + * + * @param handler view holder + */ + void inject(Object handler, View view); + + /** + * 注入fragment + */ + View inject(Object fragment, LayoutInflater inflater, ViewGroup container); +} diff --git a/app/src/main/java/org/xutils/cache/DiskCacheEntity.java b/app/src/main/java/org/xutils/cache/DiskCacheEntity.java new file mode 100644 index 0000000..62cfac0 --- /dev/null +++ b/app/src/main/java/org/xutils/cache/DiskCacheEntity.java @@ -0,0 +1,129 @@ +package org.xutils.cache; + +import org.xutils.db.annotation.Column; +import org.xutils.db.annotation.Table; + +import java.util.Date; + +/** + * Created by wyouflf on 15/8/2. + * 磁盘缓存对象 + */ +@Table(name = "disk_cache") +public final class DiskCacheEntity { + + @Column(name = "id", isId = true) + private long id; + + @Column(name = "key", property = "UNIQUE") + private String key; + + @Column(name = "path") + private String path; + + @Column(name = "textContent") + private String textContent; + + @Column(name = "bytesContent") + private byte[] bytesContent; + + // from "max-age" (since http 1.1) + @Column(name = "expires") + private long expires = Long.MAX_VALUE; + + @Column(name = "etag") + private String etag; + + @Column(name = "hits") + private long hits; + + @Column(name = "lastModify") + private Date lastModify; + + @Column(name = "lastAccess") + private long lastAccess; + + + public DiskCacheEntity() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + /*package*/ String getPath() { + return path; + } + + /*package*/ void setPath(String path) { + this.path = path; + } + + public String getTextContent() { + return textContent; + } + + public void setTextContent(String textContent) { + this.textContent = textContent; + } + + public byte[] getBytesContent() { + return bytesContent; + } + + public void setBytesContent(byte[] bytesContent) { + this.bytesContent = bytesContent; + } + + public long getExpires() { + return expires; + } + + public void setExpires(long expires) { + this.expires = expires; + } + + public String getEtag() { + return etag; + } + + public void setEtag(String etag) { + this.etag = etag; + } + + public long getHits() { + return hits; + } + + public void setHits(long hits) { + this.hits = hits; + } + + public Date getLastModify() { + return lastModify; + } + + public void setLastModify(Date lastModify) { + this.lastModify = lastModify; + } + + public long getLastAccess() { + return lastAccess == 0 ? System.currentTimeMillis() : lastAccess; + } + + public void setLastAccess(long lastAccess) { + this.lastAccess = lastAccess; + } +} diff --git a/app/src/main/java/org/xutils/cache/DiskCacheFile.java b/app/src/main/java/org/xutils/cache/DiskCacheFile.java new file mode 100644 index 0000000..021109c --- /dev/null +++ b/app/src/main/java/org/xutils/cache/DiskCacheFile.java @@ -0,0 +1,48 @@ +package org.xutils.cache; + +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.ProcessLock; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; + +/** + * Created by wyouflf on 15/8/3. + * 磁盘缓存文件, 操作完成后必须及时调用close()方法关闭. + */ +public final class DiskCacheFile extends File implements Closeable { + + private final DiskCacheEntity cacheEntity; + private final ProcessLock lock; + + /*package*/ DiskCacheFile(String path, DiskCacheEntity cacheEntity, ProcessLock lock) { + super(path); + this.cacheEntity = cacheEntity; + this.lock = lock; + } + + @Override + public void close() throws IOException { + IOUtil.closeQuietly(lock); + } + + public DiskCacheFile commit() throws IOException { + return getDiskCache().commitDiskCacheFile(this); + } + + public LruDiskCache getDiskCache() { + String dirName = this.getParentFile().getName(); + return LruDiskCache.getDiskCache(dirName); + } + + public DiskCacheEntity getCacheEntity() { + return cacheEntity; + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + this.close(); + } +} diff --git a/app/src/main/java/org/xutils/cache/LruCache.java b/app/src/main/java/org/xutils/cache/LruCache.java new file mode 100644 index 0000000..c031d55 --- /dev/null +++ b/app/src/main/java/org/xutils/cache/LruCache.java @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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 org.xutils.cache; + +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; + +/** + * Static library version of {@link android.util.LruCache}. Used to write apps + * that run on API levels prior to 12. When running on API level 12 or above, + * this implementation is still used; it does not try to switch to the + * framework's implementation. See the framework SDK documentation for a class + * overview. + */ +public class LruCache { + private final LinkedHashMap map; + + /** + * Size of this cache in units. Not necessarily the number of elements. + */ + private int size; + private int maxSize; + + private int putCount; + private int createCount; + private int evictionCount; + private int hitCount; + private int missCount; + + /** + * @param maxSize for caches that do not override {@link #sizeOf}, this is + * the maximum number of entries in the cache. For all other caches, + * this is the maximum sum of the sizes of the entries in this cache. + */ + public LruCache(int maxSize) { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + this.maxSize = maxSize; + this.map = new LinkedHashMap(0, 0.75f, true); + } + + /** + * Sets the size of the cache. + * + * @param maxSize The new maximum size. + */ + public void resize(int maxSize) { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + + synchronized (this) { + this.maxSize = maxSize; + } + trimToSize(maxSize); + } + + /** + * Returns the value for {@code key} if it exists in the cache or can be + * created by {@code #create}. If a value was returned, it is moved to the + * head of the queue. This returns null if a value is not cached and cannot + * be created. + */ + public final V get(K key) { + if (key == null) { + throw new NullPointerException("key == null"); + } + + V mapValue; + synchronized (this) { + mapValue = map.get(key); + if (mapValue != null) { + hitCount++; + return mapValue; + } + missCount++; + } + + /* + * Attempt to create a value. This may take a long time, and the map + * may be different when create() returns. If a conflicting value was + * added to the map while create() was working, we leave that value in + * the map and release the created value. + */ + + V createdValue = create(key); + if (createdValue == null) { + return null; + } + + synchronized (this) { + createCount++; + mapValue = map.put(key, createdValue); + + if (mapValue != null) { + // There was a conflict so undo that last put + map.put(key, mapValue); + } else { + size += safeSizeOf(key, createdValue); + } + } + + if (mapValue != null) { + entryRemoved(false, key, createdValue, mapValue); + return mapValue; + } else { + trimToSize(maxSize); + return createdValue; + } + } + + /** + * Caches {@code value} for {@code key}. The value is moved to the head of + * the queue. + * + * @return the previous value mapped by {@code key}. + */ + public final V put(K key, V value) { + if (key == null || value == null) { + throw new NullPointerException("key == null || value == null"); + } + + V previous; + synchronized (this) { + putCount++; + size += safeSizeOf(key, value); + previous = map.put(key, value); + if (previous != null) { + size -= safeSizeOf(key, previous); + } + } + + if (previous != null) { + entryRemoved(false, key, previous, value); + } + + trimToSize(maxSize); + return previous; + } + + /** + * Remove the eldest entries until the total of remaining entries is at or + * below the requested size. + * + * @param maxSize the maximum size of the cache before returning. May be -1 + * to evict even 0-sized elements. + */ + public void trimToSize(int maxSize) { + while (true) { + K key; + V value; + synchronized (this) { + if (size < 0 || (map.isEmpty() && size != 0)) { + throw new IllegalStateException(getClass().getName() + + ".sizeOf() is reporting inconsistent results!"); + } + + if (size <= maxSize || map.isEmpty()) { + break; + } + + Map.Entry toEvict = map.entrySet().iterator().next(); + key = toEvict.getKey(); + value = toEvict.getValue(); + map.remove(key); + size -= safeSizeOf(key, value); + evictionCount++; + } + + entryRemoved(true, key, value, null); + } + } + + /** + * Removes the entry for {@code key} if it exists. + * + * @return the previous value mapped by {@code key}. + */ + public final V remove(K key) { + if (key == null) { + throw new NullPointerException("key == null"); + } + + V previous; + synchronized (this) { + previous = map.remove(key); + if (previous != null) { + size -= safeSizeOf(key, previous); + } + } + + if (previous != null) { + entryRemoved(false, key, previous, null); + } + + return previous; + } + + /** + * Called for entries that have been evicted or removed. This method is + * invoked when a value is evicted to make space, removed by a call to + * {@link #remove}, or replaced by a call to {@link #put}. The default + * implementation does nothing. + *

The method is called without synchronization: other threads may + * access the cache while this method is executing. + * + * @param evicted true if the entry is being removed to make space, false + * if the removal was caused by a {@link #put} or {@link #remove}. + * @param newValue the new value for {@code key}, if it exists. If non-null, + * this removal was caused by a {@link #put}. Otherwise it was caused by + * an eviction or a {@link #remove}. + */ + protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) { + } + + /** + * Called after a cache miss to compute a value for the corresponding key. + * Returns the computed value or null if no value can be computed. The + * default implementation returns null. + *

The method is called without synchronization: other threads may + * access the cache while this method is executing. + *

If a value for {@code key} exists in the cache when this method + * returns, the created value will be released with {@link #entryRemoved} + * and discarded. This can occur when multiple threads request the same key + * at the same time (causing multiple values to be created), or when one + * thread calls {@link #put} while another is creating a value for the same + * key. + */ + protected V create(K key) { + return null; + } + + private int safeSizeOf(K key, V value) { + int result = sizeOf(key, value); + if (result < 0) { + throw new IllegalStateException("Negative size: " + key + "=" + value); + } + return result; + } + + /** + * Returns the size of the entry for {@code key} and {@code value} in + * user-defined units. The default implementation returns 1 so that size + * is the number of entries and max size is the maximum number of entries. + *

An entry's size must not change while it is in the cache. + */ + protected int sizeOf(K key, V value) { + return 1; + } + + /** + * Clear the cache, calling {@link #entryRemoved} on each removed entry. + */ + public final void evictAll() { + trimToSize(-1); // -1 will evict 0-sized elements + } + + /** + * For caches that do not override {@link #sizeOf}, this returns the number + * of entries in the cache. For all other caches, this returns the sum of + * the sizes of the entries in this cache. + */ + public synchronized final int size() { + return size; + } + + /** + * For caches that do not override {@link #sizeOf}, this returns the maximum + * number of entries in the cache. For all other caches, this returns the + * maximum sum of the sizes of the entries in this cache. + */ + public synchronized final int maxSize() { + return maxSize; + } + + /** + * Returns the number of times {@link #get} returned a value that was + * already present in the cache. + */ + public synchronized final int hitCount() { + return hitCount; + } + + /** + * Returns the number of times {@link #get} returned null or required a new + * value to be created. + */ + public synchronized final int missCount() { + return missCount; + } + + /** + * Returns the number of times {@link #create(Object)} returned a value. + */ + public synchronized final int createCount() { + return createCount; + } + + /** + * Returns the number of times {@link #put} was called. + */ + public synchronized final int putCount() { + return putCount; + } + + /** + * Returns the number of values that have been evicted. + */ + public synchronized final int evictionCount() { + return evictionCount; + } + + /** + * Returns a copy of the current contents of the cache, ordered from least + * recently accessed to most recently accessed. + */ + public synchronized final Map snapshot() { + return new LinkedHashMap(map); + } + + @Override + public synchronized final String toString() { + int accesses = hitCount + missCount; + int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0; + return String.format(Locale.getDefault(), + "LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]", + maxSize, hitCount, missCount, hitPercent); + } +} diff --git a/app/src/main/java/org/xutils/cache/LruDiskCache.java b/app/src/main/java/org/xutils/cache/LruDiskCache.java new file mode 100644 index 0000000..8101a63 --- /dev/null +++ b/app/src/main/java/org/xutils/cache/LruDiskCache.java @@ -0,0 +1,391 @@ +package org.xutils.cache; + + +import android.text.TextUtils; + +import org.xutils.DbManager; +import org.xutils.common.task.PriorityExecutor; +import org.xutils.common.util.FileUtil; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.common.util.MD5; +import org.xutils.common.util.ProcessLock; +import org.xutils.config.DbConfigs; +import org.xutils.db.sqlite.WhereBuilder; +import org.xutils.ex.FileLockedException; +import org.xutils.x; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * Created by wyouflf on 15/7/23. + * 使用sqlite索引实现的LruDiskCache + */ +public final class LruDiskCache { + + /** + * key: cacheDirName + */ + private static final HashMap DISK_CACHE_MAP = new HashMap(5); + + private static final int LIMIT_COUNT = 5000; // 限制最多5000条数据 + private static final long LIMIT_SIZE = 1024L * 1024L * 100L; // 限制最多100M文件 + + private static final int LOCK_WAIT = 1000 * 3; // 3s + private static final String CACHE_DIR_NAME = "xUtils_cache"; + private static final String TEMP_FILE_SUFFIX = ".tmp"; + + private boolean available = false; + private DbManager cacheDb; + private File cacheDir; + private long diskCacheSize = LIMIT_SIZE; + private final Executor trimExecutor = new PriorityExecutor(1, true); + + private long lastTrimTime = 0L; + private static final long TRIM_TIME_SPAN = 1000; + + public synchronized static LruDiskCache getDiskCache(String dirName) { + if (TextUtils.isEmpty(dirName)) dirName = CACHE_DIR_NAME; + LruDiskCache cache = DISK_CACHE_MAP.get(dirName); + if (cache == null) { + cache = new LruDiskCache(dirName); + DISK_CACHE_MAP.put(dirName, cache); + } + return cache; + } + + private LruDiskCache(String dirName) { + try { + this.cacheDir = FileUtil.getCacheDir(dirName); + if (this.cacheDir != null && (this.cacheDir.exists() || this.cacheDir.mkdirs())) { + available = true; + } + this.cacheDb = x.getDb(DbConfigs.HTTP.getConfig()); + } catch (Throwable ex) { + available = false; + LogUtil.e(ex.getMessage(), ex); + } + deleteNoIndexFiles(); + } + + public LruDiskCache setMaxSize(long maxSize) { + if (maxSize > 0L) { + long diskFreeSize = FileUtil.getDiskAvailableSize(); + if (diskFreeSize > maxSize) { + diskCacheSize = maxSize; + } else { + diskCacheSize = diskFreeSize; + } + } + return this; + } + + public DiskCacheEntity get(String key) { + if (!available || TextUtils.isEmpty(key)) return null; + + DiskCacheEntity result = null; + try { + result = this.cacheDb.selector(DiskCacheEntity.class) + .where("key", "=", key).findFirst(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + if (result != null) { + + if (result.getExpires() < System.currentTimeMillis()) { + return null; + } + + { // update hint & lastAccess... + final DiskCacheEntity finalResult = result; + trimExecutor.execute(new Runnable() { + @Override + public void run() { + finalResult.setHits(finalResult.getHits() + 1); + finalResult.setLastAccess(System.currentTimeMillis()); + try { + cacheDb.update(finalResult, "hits", "lastAccess"); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + }); + } + + } + + return result; + } + + public void put(DiskCacheEntity entity) { + if (!available + || entity == null + || TextUtils.isEmpty(entity.getTextContent()) + || entity.getExpires() < System.currentTimeMillis()) { + return; + } + + try { + cacheDb.replace(entity); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + trimSize(); + } + + public DiskCacheFile getDiskCacheFile(String key) throws InterruptedException { + if (!available || TextUtils.isEmpty(key)) { + return null; + } + + DiskCacheFile result = null; + DiskCacheEntity entity = get(key); + if (entity != null && new File(entity.getPath()).exists()) { + ProcessLock processLock = ProcessLock.tryLock(entity.getPath(), false, LOCK_WAIT); + if (processLock != null && processLock.isValid()) { + result = new DiskCacheFile(entity.getPath(), entity, processLock); + if (!result.exists()) { + try { + cacheDb.delete(entity); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + result = null; + } + } + } + + return result; + } + + public DiskCacheFile createDiskCacheFile(DiskCacheEntity entity) throws IOException { + if (!available || entity == null) { + return null; + } + + DiskCacheFile result = null; + + entity.setPath(new File(this.cacheDir, MD5.md5(entity.getKey())).getAbsolutePath()); + String tempFilePath = entity.getPath() + TEMP_FILE_SUFFIX; + ProcessLock processLock = ProcessLock.tryLock(tempFilePath, true); + if (processLock != null && processLock.isValid()) { + result = new DiskCacheFile(tempFilePath, entity, processLock); + if (!result.getParentFile().exists()) { + result.mkdirs(); + } + } else { + throw new FileLockedException(entity.getPath()); + } + + return result; + } + + public void clearCacheFiles() { + IOUtil.deleteFileOrDir(cacheDir); + } + + /** + * 添加缓存文件 + * + * @param cacheFile + */ + /*package*/ DiskCacheFile commitDiskCacheFile(DiskCacheFile cacheFile) throws IOException { + if (!available || cacheFile == null) { + return cacheFile; + } + + DiskCacheFile result = null; + DiskCacheEntity cacheEntity = cacheFile.getCacheEntity(); + if (cacheFile.getName().endsWith(TEMP_FILE_SUFFIX)) { // is temp file + ProcessLock processLock = null; + DiskCacheFile destFile = null; + try { + String destPath = cacheEntity.getPath(); + processLock = ProcessLock.tryLock(destPath, true, LOCK_WAIT); + if (processLock != null && processLock.isValid()) { // lock + destFile = new DiskCacheFile(destPath, cacheEntity, processLock); + if (cacheFile.renameTo(destFile)) { + try { + result = destFile; + cacheDb.replace(cacheEntity); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + trimSize(); + } else { + throw new IOException("rename:" + cacheFile.getAbsolutePath()); + } + } else { + throw new FileLockedException(destPath); + } + } catch (InterruptedException ex) { + result = cacheFile; + LogUtil.e(ex.getMessage(), ex); + } finally { + if (result == null) { + result = cacheFile; + IOUtil.closeQuietly(destFile); + IOUtil.closeQuietly(processLock); + IOUtil.deleteFileOrDir(destFile); + } else { + IOUtil.closeQuietly(cacheFile); + IOUtil.deleteFileOrDir(cacheFile); + } + } + } else { + result = cacheFile; + } + + return result; + } + + private void trimSize() { + trimExecutor.execute(new Runnable() { + @Override + public void run() { + if (!available) return; + + long current = System.currentTimeMillis(); + if (current - lastTrimTime < TRIM_TIME_SPAN) { + return; + } else { + lastTrimTime = current; + } + + // trim expires + deleteExpiry(); + + // trim db + try { + int count = (int) cacheDb.selector(DiskCacheEntity.class).count(); + if (count > LIMIT_COUNT + 10) { + List rmList = cacheDb.selector(DiskCacheEntity.class) + .orderBy("lastAccess").orderBy("hits") + .limit(count - LIMIT_COUNT).offset(0).findAll(); + if (rmList != null && rmList.size() > 0) { + // delete cache files + for (DiskCacheEntity entity : rmList) { + try { + // delete db entity + cacheDb.delete(entity); + // delete cache files + String path = entity.getPath(); + if (!TextUtils.isEmpty(path)) { + deleteFileWithLock(path); + deleteFileWithLock(path + TEMP_FILE_SUFFIX); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + // trim disk + try { + while (FileUtil.getFileOrDirSize(cacheDir) > diskCacheSize) { + List rmList = cacheDb.selector(DiskCacheEntity.class) + .orderBy("lastAccess").orderBy("hits").limit(10).offset(0).findAll(); + if (rmList != null && rmList.size() > 0) { + // delete cache files + for (DiskCacheEntity entity : rmList) { + try { + // delete db entity + cacheDb.delete(entity); + // delete cache files + String path = entity.getPath(); + if (!TextUtils.isEmpty(path)) { + deleteFileWithLock(path); + deleteFileWithLock(path + TEMP_FILE_SUFFIX); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + }); + } + + private void deleteExpiry() { + if (!available) return; + + try { + WhereBuilder whereBuilder = WhereBuilder.b("expires", "<", System.currentTimeMillis()); + List rmList = cacheDb.selector(DiskCacheEntity.class).where(whereBuilder).findAll(); + // delete db entities + cacheDb.delete(DiskCacheEntity.class, whereBuilder); + if (rmList != null && rmList.size() > 0) { + // delete cache files + for (DiskCacheEntity entity : rmList) { + String path = entity.getPath(); + if (!TextUtils.isEmpty(path)) { + deleteFileWithLock(path); + } + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + /** + * 清理未被数据库索引的历史缓存文件 + */ + private void deleteNoIndexFiles() { + trimExecutor.execute(new Runnable() { + @Override + public void run() { + if (!available) return; + + try { + File[] fileList = cacheDir.listFiles(); + if (fileList != null) { + for (File file : fileList) { + try { + long count = cacheDb.selector(DiskCacheEntity.class) + .where("path", "=", file.getAbsolutePath()).count(); + if (count < 1) { + IOUtil.deleteFileOrDir(file); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + }); + } + + private boolean deleteFileWithLock(String path) { + ProcessLock processLock = null; + try { + processLock = ProcessLock.tryLock(path, true); + if (processLock != null && processLock.isValid()) { // lock + File file = new File(path); + return IOUtil.deleteFileOrDir(file); + } + } finally { + IOUtil.closeQuietly(processLock); + } + return false; + } +} diff --git a/app/src/main/java/org/xutils/common/Callback.java b/app/src/main/java/org/xutils/common/Callback.java new file mode 100644 index 0000000..8abd2fd --- /dev/null +++ b/app/src/main/java/org/xutils/common/Callback.java @@ -0,0 +1,72 @@ +package org.xutils.common; + +import java.lang.reflect.Type; + +/** + * Created by wyouflf on 15/6/5. + * 通用回调接口 + */ +public interface Callback { + + public interface CommonCallback extends Callback { + void onSuccess(ResultType result); + + void onError(Throwable ex, boolean isOnCallback); + + void onCancelled(CancelledException cex); + + void onFinished(); + } + + public interface TypedCallback extends CommonCallback { + Type getLoadType(); + } + + public interface CacheCallback extends CommonCallback { + boolean onCache(ResultType result); + } + + public interface ProxyCacheCallback extends CacheCallback { + boolean onlyCache(); + } + + public interface PrepareCallback extends CommonCallback { + ResultType prepare(PrepareType rawData) throws Throwable; + } + + public interface ProgressCallback extends CommonCallback { + void onWaiting(); + + void onStarted(); + + void onLoading(long total, long current, boolean isDownloading); + } + + public interface GroupCallback extends Callback { + void onSuccess(ItemType item); + + void onError(ItemType item, Throwable ex, boolean isOnCallback); + + void onCancelled(ItemType item, CancelledException cex); + + void onFinished(ItemType item); + + void onAllFinished(); + } + + public interface Callable { + void call(ResultType result); + } + + public interface Cancelable { + void cancel(); + + boolean isCancelled(); + } + + public static class CancelledException extends RuntimeException { + public CancelledException(String detailMessage) { + super(detailMessage); + } + } +} diff --git a/app/src/main/java/org/xutils/common/TaskController.java b/app/src/main/java/org/xutils/common/TaskController.java new file mode 100644 index 0000000..940cee8 --- /dev/null +++ b/app/src/main/java/org/xutils/common/TaskController.java @@ -0,0 +1,54 @@ +package org.xutils.common; + +import org.xutils.common.task.AbsTask; + +/** + * Created by wyouflf on 15/6/11. + * 任务管理接口 + */ +public interface TaskController { + + /** + * 在UI线程执行runnable. + * 如果已在UI线程, 则直接执行. + */ + void autoPost(Runnable runnable); + + /** + * 在UI线程执行runnable. + * post到msg queue. + */ + void post(Runnable runnable); + + /** + * 在UI线程执行runnable. + * + * @param delayMillis 延迟时间(单位毫秒) + */ + void postDelayed(Runnable runnable, long delayMillis); + + /** + * 在后台线程执行runnable + */ + void run(Runnable runnable); + + /** + * 移除post或postDelayed提交的, 未执行的runnable + */ + void removeCallbacks(Runnable runnable); + + /** + * 开始一个异步任务 + */ + AbsTask start(AbsTask task); + + /** + * 同步执行一个任务 + */ + T startSync(AbsTask task) throws Throwable; + + /** + * 批量执行异步任务 + */ + > Callback.Cancelable startTasks(Callback.GroupCallback groupCallback, T... tasks); +} diff --git a/app/src/main/java/org/xutils/common/task/AbsTask.java b/app/src/main/java/org/xutils/common/task/AbsTask.java new file mode 100644 index 0000000..37cf580 --- /dev/null +++ b/app/src/main/java/org/xutils/common/task/AbsTask.java @@ -0,0 +1,154 @@ +package org.xutils.common.task; + +import android.os.Looper; + +import org.xutils.common.Callback; + +import java.util.concurrent.Executor; + + +/** + * Created by wyouflf on 15/6/5. + * 异步任务基类 + * + * @param 任务返回值类型 + */ +public abstract class AbsTask implements Callback.Cancelable { + + private TaskProxy taskProxy = null; + private final Callback.Cancelable cancelHandler; + + private volatile boolean isCancelled = false; + private volatile State state = State.IDLE; + private ResultType result; + + public AbsTask() { + this(null); + } + + public AbsTask(Callback.Cancelable cancelHandler) { + this.cancelHandler = cancelHandler; + } + + protected abstract ResultType doBackground() throws Throwable; + + protected abstract void onSuccess(ResultType result); + + protected abstract void onError(Throwable ex, boolean isCallbackError); + + protected void onWaiting() { + } + + protected void onStarted() { + } + + protected void onUpdate(int flag, Object... args) { + } + + protected void onCancelled(Callback.CancelledException cex) { + } + + protected void onFinished() { + } + + public Priority getPriority() { + return null; + } + + public Executor getExecutor() { + return null; + } + + public Looper customLooper() { + return null; + } + + protected final void update(int flag, Object... args) { + if (taskProxy != null) { + taskProxy.onUpdate(flag, args); + } + } + + /** + * invoked via cancel() + */ + protected void cancelWorks() { + } + + /** + * 取消任务时是否不等待任务彻底结束, 立即收到取消的通知. + * + * @return 是否立即响应取消回调 + */ + protected boolean isCancelFast() { + return false; + } + + @Override + public final void cancel() { + if (this.isCancelled) return; + synchronized (this) { + if (this.isCancelled) return; + this.isCancelled = true; + cancelWorks(); + if (cancelHandler != null && !cancelHandler.isCancelled()) { + cancelHandler.cancel(); + } + if (this.state == State.WAITING || (this.state == State.STARTED && isCancelFast())) { + if (taskProxy != null) { + taskProxy.onCancelled(new Callback.CancelledException("cancelled by user")); + taskProxy.onFinished(); + } else if (this instanceof TaskProxy) { + this.onCancelled(new Callback.CancelledException("cancelled by user")); + this.onFinished(); + } + } + } + } + + @Override + public final boolean isCancelled() { + return isCancelled || state == State.CANCELLED || + (cancelHandler != null && cancelHandler.isCancelled()); + } + + public final boolean isFinished() { + return this.state.value() > State.STARTED.value(); + } + + public final State getState() { + return state; + } + + public final ResultType getResult() { + return result; + } + + /*package*/ + void setState(State state) { + this.state = state; + } + + /*package*/ + final void setTaskProxy(TaskProxy taskProxy) { + this.taskProxy = taskProxy; + } + + /*package*/ + final void setResult(ResultType result) { + this.result = result; + } + + public enum State { + IDLE(0), WAITING(1), STARTED(2), SUCCESS(3), CANCELLED(4), ERROR(5); + private final int value; + + private State(int value) { + this.value = value; + } + + public int value() { + return value; + } + } +} diff --git a/app/src/main/java/org/xutils/common/task/Priority.java b/app/src/main/java/org/xutils/common/task/Priority.java new file mode 100644 index 0000000..ce61044 --- /dev/null +++ b/app/src/main/java/org/xutils/common/task/Priority.java @@ -0,0 +1,9 @@ +package org.xutils.common.task; + +/** + * Created by wyouflf on 15/6/5. + * 任务的优先级 + */ +public enum Priority { + UI_TOP, UI_NORMAL, UI_LOW, DEFAULT, BG_TOP, BG_NORMAL, BG_LOW; +} diff --git a/app/src/main/java/org/xutils/common/task/PriorityExecutor.java b/app/src/main/java/org/xutils/common/task/PriorityExecutor.java new file mode 100644 index 0000000..e342b1e --- /dev/null +++ b/app/src/main/java/org/xutils/common/task/PriorityExecutor.java @@ -0,0 +1,113 @@ +package org.xutils.common.task; + +import java.util.Comparator; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Created by wyouflf on 15/6/5. + * 支持优先级的线程池管理类 + */ +public class PriorityExecutor implements Executor { + + private static final int CORE_POOL_SIZE = 5; + private static final int MAXIMUM_POOL_SIZE = 256; + private static final int KEEP_ALIVE = 1; + private static final AtomicLong SEQ_SEED = new AtomicLong(0); + + private static final ThreadFactory sThreadFactory = new ThreadFactory() { + private final AtomicInteger mCount = new AtomicInteger(1); + + @Override + public Thread newThread(Runnable runnable) { + return new Thread(runnable, "xTID#" + mCount.getAndIncrement()); + } + }; + + private static final Comparator FIFO_CMP = new Comparator() { + @Override + public int compare(Runnable lhs, Runnable rhs) { + if (lhs instanceof PriorityRunnable && rhs instanceof PriorityRunnable) { + PriorityRunnable lpr = ((PriorityRunnable) lhs); + PriorityRunnable rpr = ((PriorityRunnable) rhs); + int result = lpr.priority.ordinal() - rpr.priority.ordinal(); + return result == 0 ? (int) (lpr.SEQ - rpr.SEQ) : result; + } else { + return 0; + } + } + }; + + private static final Comparator FILO_CMP = new Comparator() { + @Override + public int compare(Runnable lhs, Runnable rhs) { + if (lhs instanceof PriorityRunnable && rhs instanceof PriorityRunnable) { + PriorityRunnable lpr = ((PriorityRunnable) lhs); + PriorityRunnable rpr = ((PriorityRunnable) rhs); + int result = lpr.priority.ordinal() - rpr.priority.ordinal(); + return result == 0 ? (int) (rpr.SEQ - lpr.SEQ) : result; + } else { + return 0; + } + } + }; + + private final ThreadPoolExecutor mThreadPoolExecutor; + + /** + * 默认工作线程数5 + * + * @param fifo 优先级相同时, 等待队列的是否优先执行先加入的任务. + */ + public PriorityExecutor(boolean fifo) { + this(CORE_POOL_SIZE, fifo); + } + + /** + * @param poolSize 工作线程数 + * @param fifo 优先级相同时, 等待队列的是否优先执行先加入的任务. + */ + public PriorityExecutor(int poolSize, boolean fifo) { + BlockingQueue mPoolWorkQueue = + new PriorityBlockingQueue(MAXIMUM_POOL_SIZE, fifo ? FIFO_CMP : FILO_CMP); + mThreadPoolExecutor = new ThreadPoolExecutor( + poolSize, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE, + TimeUnit.SECONDS, + mPoolWorkQueue, + sThreadFactory); + } + + public int getPoolSize() { + return mThreadPoolExecutor.getCorePoolSize(); + } + + public void setPoolSize(int poolSize) { + if (poolSize > 0) { + mThreadPoolExecutor.setCorePoolSize(poolSize); + } + } + + public ThreadPoolExecutor getThreadPoolExecutor() { + return mThreadPoolExecutor; + } + + public boolean isBusy() { + return mThreadPoolExecutor.getActiveCount() >= mThreadPoolExecutor.getCorePoolSize(); + } + + @Override + public void execute(Runnable runnable) { + if (runnable instanceof PriorityRunnable) { + ((PriorityRunnable) runnable).SEQ = SEQ_SEED.getAndIncrement(); + } + mThreadPoolExecutor.execute(runnable); + } +} diff --git a/app/src/main/java/org/xutils/common/task/PriorityRunnable.java b/app/src/main/java/org/xutils/common/task/PriorityRunnable.java new file mode 100644 index 0000000..0fd3521 --- /dev/null +++ b/app/src/main/java/org/xutils/common/task/PriorityRunnable.java @@ -0,0 +1,23 @@ +package org.xutils.common.task; + +/** + * Created by wyouflf on 15/6/5. + * 带有优先级的Runnable类型(仅在task包内可用) + */ +/*package*/ class PriorityRunnable implements Runnable { + + /*package*/ long SEQ; + + public final Priority priority; + private final Runnable runnable; + + public PriorityRunnable(Priority priority, Runnable runnable) { + this.priority = priority == null ? Priority.DEFAULT : priority; + this.runnable = runnable; + } + + @Override + public final void run() { + this.runnable.run(); + } +} diff --git a/app/src/main/java/org/xutils/common/task/TaskControllerImpl.java b/app/src/main/java/org/xutils/common/task/TaskControllerImpl.java new file mode 100644 index 0000000..71baf7d --- /dev/null +++ b/app/src/main/java/org/xutils/common/task/TaskControllerImpl.java @@ -0,0 +1,258 @@ +package org.xutils.common.task; + +import android.os.Looper; + +import org.xutils.common.Callback; +import org.xutils.common.TaskController; +import org.xutils.common.util.LogUtil; +import org.xutils.x; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by wyouflf on 15/6/5. + * 异步任务的管理类 + */ +public final class TaskControllerImpl implements TaskController { + + private TaskControllerImpl() { + } + + private static volatile TaskController instance; + + public static void registerInstance() { + if (instance == null) { + synchronized (TaskController.class) { + if (instance == null) { + instance = new TaskControllerImpl(); + } + } + } + x.Ext.setTaskController(instance); + } + + /** + * run task + */ + @Override + public AbsTask start(AbsTask task) { + TaskProxy proxy = null; + if (task instanceof TaskProxy) { + proxy = (TaskProxy) task; + } else { + proxy = new TaskProxy(task); + } + try { + proxy.doBackground(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + return proxy; + } + + @Override + public T startSync(AbsTask task) throws Throwable { + T result = null; + try { + task.onWaiting(); + task.onStarted(); + result = task.doBackground(); + task.onSuccess(result); + } catch (Callback.CancelledException cex) { + task.onCancelled(cex); + } catch (Throwable ex) { + task.onError(ex, false); + throw ex; + } finally { + task.onFinished(); + } + return result; + } + + @Override + @SuppressWarnings("unchecked") + public > Callback.Cancelable startTasks( + final Callback.GroupCallback groupCallback, final T... tasks) { + + if (tasks == null) { + throw new IllegalArgumentException("task must not be null"); + } + + final Runnable callIfOnAllFinished = new Runnable() { + private final int total = tasks.length; + private final AtomicInteger count = new AtomicInteger(0); + + @Override + public void run() { + if (count.incrementAndGet() == total) { + if (groupCallback != null) { + try { + groupCallback.onAllFinished(); + } catch (Throwable ex) { + try { + groupCallback.onError(null, ex, true); + } catch (Throwable throwable) { + LogUtil.e(throwable.getMessage(), throwable); + } + } + } + } + } + }; + + for (final T task : tasks) { + start(new TaskProxy(task) { + @Override + protected void onSuccess(Object result) { + super.onSuccess(result); + post(new Runnable() { + @Override + public void run() { + if (groupCallback != null) { + try { + groupCallback.onSuccess(task); + } catch (Throwable ex) { + try { + groupCallback.onError(task, ex, true); + } catch (Throwable throwable) { + LogUtil.e(throwable.getMessage(), throwable); + } + } + } + } + }); + } + + @Override + protected void onCancelled(final Callback.CancelledException cex) { + super.onCancelled(cex); + post(new Runnable() { + @Override + public void run() { + if (groupCallback != null) { + try { + groupCallback.onCancelled(task, cex); + } catch (Throwable ex) { + try { + groupCallback.onError(task, ex, true); + } catch (Throwable throwable) { + LogUtil.e(throwable.getMessage(), throwable); + } + } + } + } + }); + } + + @Override + protected void onError(final Throwable ex, final boolean isCallbackError) { + super.onError(ex, isCallbackError); + post(new Runnable() { + @Override + public void run() { + if (groupCallback != null) { + try { + groupCallback.onError(task, ex, isCallbackError); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + }); + } + + @Override + protected void onFinished() { + super.onFinished(); + post(new Runnable() { + @Override + public void run() { + try { + if (groupCallback != null) { + groupCallback.onFinished(task); + } + } catch (Throwable ex) { + try { + groupCallback.onError(task, ex, true); + } catch (Throwable throwable) { + LogUtil.e(throwable.getMessage(), throwable); + } + } finally { + callIfOnAllFinished.run(); + } + } + }); + } + }); + } + + return new Callback.Cancelable() { + + @Override + public void cancel() { + for (T task : tasks) { + task.cancel(); + } + } + + @Override + public boolean isCancelled() { + boolean isCancelled = true; + for (T task : tasks) { + if (!task.isCancelled()) { + isCancelled = false; + } + } + return isCancelled; + } + }; + } + + @Override + public void autoPost(Runnable runnable) { + if (runnable == null) return; + if (Thread.currentThread() == Looper.getMainLooper().getThread()) { + runnable.run(); + } else { + TaskProxy.sHandler.post(runnable); + } + } + + /** + * run in UI thread + */ + @Override + public void post(Runnable runnable) { + if (runnable == null) return; + TaskProxy.sHandler.post(runnable); + } + + /** + * run in UI thread + */ + @Override + public void postDelayed(Runnable runnable, long delayMillis) { + if (runnable == null) return; + TaskProxy.sHandler.postDelayed(runnable, delayMillis); + } + + /** + * run in background thread + */ + @Override + public void run(Runnable runnable) { + if (!TaskProxy.sDefaultExecutor.isBusy()) { + TaskProxy.sDefaultExecutor.execute(runnable); + } else { + new Thread(runnable).start(); + } + } + + /** + * 移除post或postDelayed提交的, 未执行的runnable + */ + @Override + public void removeCallbacks(Runnable runnable) { + TaskProxy.sHandler.removeCallbacks(runnable); + } +} diff --git a/app/src/main/java/org/xutils/common/task/TaskProxy.java b/app/src/main/java/org/xutils/common/task/TaskProxy.java new file mode 100644 index 0000000..4d23154 --- /dev/null +++ b/app/src/main/java/org/xutils/common/task/TaskProxy.java @@ -0,0 +1,254 @@ +package org.xutils.common.task; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import org.xutils.common.Callback; +import org.xutils.common.util.LogUtil; +import org.xutils.x; + +import java.util.concurrent.Executor; + +/** + * 异步任务的代理类(仅在task包内可用) + * + * @param + */ +/*package*/ class TaskProxy extends AbsTask { + + /*package*/ static final InternalHandler sHandler = new InternalHandler(); + /*package*/ static final PriorityExecutor sDefaultExecutor = new PriorityExecutor(true); + + private final AbsTask task; + private final Executor executor; + private final Handler handler; + private volatile boolean callOnCanceled = false; + private volatile boolean callOnFinished = false; + + /*package*/ TaskProxy(AbsTask task) { + super(task); + this.task = task; + this.task.setTaskProxy(this); + this.setTaskProxy(null); + + // set handler + Looper looper = task.customLooper(); + if (looper != null) { + handler = new InternalHandler(looper); + } else { + handler = sHandler; + } + + // set executor + Executor taskExecutor = task.getExecutor(); + if (taskExecutor == null) { + taskExecutor = sDefaultExecutor; + } + this.executor = taskExecutor; + } + + @Override + protected final ResultType doBackground() throws Throwable { + this.onWaiting(); + PriorityRunnable runnable = new PriorityRunnable( + task.getPriority(), + new Runnable() { + @Override + public void run() { + try { + // 等待过程中取消 + if (callOnCanceled || TaskProxy.this.isCancelled()) { + throw new Callback.CancelledException(""); + } + + // start running + TaskProxy.this.onStarted(); + + if (TaskProxy.this.isCancelled()) { // 开始时取消 + throw new Callback.CancelledException(""); + } + + // 执行task, 得到结果. + task.setResult(task.doBackground()); + TaskProxy.this.setResult(task.getResult()); + + // 未在doBackground过程中取消成功 + if (TaskProxy.this.isCancelled()) { + throw new Callback.CancelledException(""); + } + + // 执行成功 + TaskProxy.this.onSuccess(task.getResult()); + } catch (Callback.CancelledException cex) { + TaskProxy.this.onCancelled(cex); + } catch (Throwable ex) { + TaskProxy.this.onError(ex, false); + } finally { + TaskProxy.this.onFinished(); + } + } + }); + this.executor.execute(runnable); + return null; + } + + @Override + protected void onWaiting() { + this.setState(State.WAITING); + handler.obtainMessage(MSG_WHAT_ON_WAITING, this).sendToTarget(); + } + + @Override + protected void onStarted() { + this.setState(State.STARTED); + handler.obtainMessage(MSG_WHAT_ON_START, this).sendToTarget(); + } + + @Override + protected void onSuccess(ResultType result) { + this.setState(State.SUCCESS); + handler.obtainMessage(MSG_WHAT_ON_SUCCESS, this).sendToTarget(); + } + + @Override + protected void onError(Throwable ex, boolean isCallbackError) { + this.setState(State.ERROR); + handler.obtainMessage(MSG_WHAT_ON_ERROR, new ArgsObj(this, ex)).sendToTarget(); + } + + @Override + protected void onUpdate(int flag, Object... args) { + // obtainMessage(int what, int arg1, int arg2, Object obj), arg2 not be used. + handler.obtainMessage(MSG_WHAT_ON_UPDATE, flag, flag, new ArgsObj(this, args)).sendToTarget(); + } + + @Override + protected void onCancelled(Callback.CancelledException cex) { + this.setState(State.CANCELLED); + handler.obtainMessage(MSG_WHAT_ON_CANCEL, new ArgsObj(this, cex)).sendToTarget(); + } + + @Override + protected void onFinished() { + handler.obtainMessage(MSG_WHAT_ON_FINISHED, this).sendToTarget(); + } + + @Override + /*package*/ final void setState(State state) { + super.setState(state); + this.task.setState(state); + } + + @Override + public final Priority getPriority() { + return task.getPriority(); + } + + @Override + public final Executor getExecutor() { + return this.executor; + } + + // ########################### inner type ############################# + private static class ArgsObj { + final TaskProxy taskProxy; + final Object[] args; + + public ArgsObj(TaskProxy taskProxy, Object... args) { + this.taskProxy = taskProxy; + this.args = args; + } + } + + private final static int MSG_WHAT_BASE = 1000000000; + private final static int MSG_WHAT_ON_WAITING = MSG_WHAT_BASE + 1; + private final static int MSG_WHAT_ON_START = MSG_WHAT_BASE + 2; + private final static int MSG_WHAT_ON_SUCCESS = MSG_WHAT_BASE + 3; + private final static int MSG_WHAT_ON_ERROR = MSG_WHAT_BASE + 4; + private final static int MSG_WHAT_ON_UPDATE = MSG_WHAT_BASE + 5; + private final static int MSG_WHAT_ON_CANCEL = MSG_WHAT_BASE + 6; + private final static int MSG_WHAT_ON_FINISHED = MSG_WHAT_BASE + 7; + + /*package*/ final static class InternalHandler extends Handler { + + private InternalHandler() { + super(Looper.getMainLooper()); + } + + private InternalHandler(Looper looper) { + super(looper); + } + + @Override + @SuppressWarnings("unchecked") + public void handleMessage(Message msg) { + if (msg.obj == null) { + throw new IllegalArgumentException("msg must not be null"); + } + TaskProxy taskProxy = null; + Object[] args = null; + if (msg.obj instanceof TaskProxy) { + taskProxy = (TaskProxy) msg.obj; + } else if (msg.obj instanceof ArgsObj) { + ArgsObj argsObj = (ArgsObj) msg.obj; + taskProxy = argsObj.taskProxy; + args = argsObj.args; + } + if (taskProxy == null) { + throw new RuntimeException("msg.obj not instanceof TaskProxy"); + } + + try { + switch (msg.what) { + case MSG_WHAT_ON_WAITING: { + taskProxy.task.onWaiting(); + break; + } + case MSG_WHAT_ON_START: { + taskProxy.task.onStarted(); + break; + } + case MSG_WHAT_ON_SUCCESS: { + taskProxy.task.onSuccess(taskProxy.getResult()); + break; + } + case MSG_WHAT_ON_ERROR: { + assert args != null; + Throwable throwable = (Throwable) args[0]; + LogUtil.d(throwable.getMessage(), throwable); + taskProxy.task.onError(throwable, false); + break; + } + case MSG_WHAT_ON_UPDATE: { + taskProxy.task.onUpdate(msg.arg1, args); + break; + } + case MSG_WHAT_ON_CANCEL: { + if (taskProxy.callOnCanceled) return; + taskProxy.callOnCanceled = true; + assert args != null; + taskProxy.task.onCancelled((org.xutils.common.Callback.CancelledException) args[0]); + break; + } + case MSG_WHAT_ON_FINISHED: { + if (taskProxy.callOnFinished) return; + taskProxy.callOnFinished = true; + taskProxy.task.onFinished(); + break; + } + default: { + break; + } + } + } catch (Throwable ex) { + taskProxy.setState(State.ERROR); + if (msg.what != MSG_WHAT_ON_ERROR) { + taskProxy.task.onError(ex, true); + } else if (x.isDebug()) { + throw new RuntimeException(ex); + } + } + } + } +} diff --git a/app/src/main/java/org/xutils/common/util/DensityUtil.java b/app/src/main/java/org/xutils/common/util/DensityUtil.java new file mode 100644 index 0000000..c32a5fa --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/DensityUtil.java @@ -0,0 +1,44 @@ +package org.xutils.common.util; + +import org.xutils.x; + + +public final class DensityUtil { + + private static float density = -1F; + private static int widthPixels = -1; + private static int heightPixels = -1; + + private DensityUtil() { + } + + public static float getDensity() { + if (density <= 0F) { + density = x.app().getResources().getDisplayMetrics().density; + } + return density; + } + + public static int dip2px(float dpValue) { + return (int) (dpValue * getDensity() + 0.5F); + } + + public static int px2dip(float pxValue) { + return (int) (pxValue / getDensity() + 0.5F); + } + + public static int getScreenWidth() { + if (widthPixels <= 0) { + widthPixels = x.app().getResources().getDisplayMetrics().widthPixels; + } + return widthPixels; + } + + + public static int getScreenHeight() { + if (heightPixels <= 0) { + heightPixels = x.app().getResources().getDisplayMetrics().heightPixels; + } + return heightPixels; + } +} diff --git a/app/src/main/java/org/xutils/common/util/DoubleKeyValueMap.java b/app/src/main/java/org/xutils/common/util/DoubleKeyValueMap.java new file mode 100644 index 0000000..76fee5f --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/DoubleKeyValueMap.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.common.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Created with IntelliJ IDEA. + * User: wyouflf + * Date: 13-6-19 + * Time: PM 1:18 + */ +public class DoubleKeyValueMap { + + private final ConcurrentHashMap> k1_k2V_map; + + public DoubleKeyValueMap() { + this.k1_k2V_map = new ConcurrentHashMap>(); + } + + public void put(K1 key1, K2 key2, V value) { + if (key1 == null || key2 == null || value == null) return; + if (k1_k2V_map.containsKey(key1)) { + ConcurrentHashMap k2V_map = k1_k2V_map.get(key1); + if (k2V_map != null) { + k2V_map.put(key2, value); + } else { + k2V_map = new ConcurrentHashMap(); + k2V_map.put(key2, value); + k1_k2V_map.put(key1, k2V_map); + } + } else { + ConcurrentHashMap k2V_map = new ConcurrentHashMap(); + k2V_map.put(key2, value); + k1_k2V_map.put(key1, k2V_map); + } + } + + public Set getFirstKeys() { + return k1_k2V_map.keySet(); + } + + public ConcurrentHashMap get(K1 key1) { + return k1_k2V_map.get(key1); + } + + public V get(K1 key1, K2 key2) { + ConcurrentHashMap k2_v = k1_k2V_map.get(key1); + return k2_v == null ? null : k2_v.get(key2); + } + + public Collection getAllValues(K1 key1) { + ConcurrentHashMap k2_v = k1_k2V_map.get(key1); + return k2_v == null ? null : k2_v.values(); + } + + public Collection getAllValues() { + Collection result = null; + Set k1Set = k1_k2V_map.keySet(); + if (k1Set != null) { + result = new ArrayList(); + for (K1 k1 : k1Set) { + ConcurrentHashMap value1 = k1_k2V_map.get(k1); + if (value1 != null) { + Collection values = value1.values(); + if (values != null) { + result.addAll(values); + } + } + } + } + return result; + } + + public boolean containsKey(K1 key1, K2 key2) { + if (k1_k2V_map.containsKey(key1)) { + ConcurrentHashMap value1 = k1_k2V_map.get(key1); + if (value1 != null) { + return value1.containsKey(key2); + } + } + return false; + } + + public boolean containsKey(K1 key1) { + return k1_k2V_map.containsKey(key1); + } + + public int size() { + if (k1_k2V_map.size() == 0) return 0; + + int result = 0; + for (ConcurrentHashMap k2V_map : k1_k2V_map.values()) { + result += k2V_map.size(); + } + return result; + } + + public void remove(K1 key1) { + k1_k2V_map.remove(key1); + } + + public void remove(K1 key1, K2 key2) { + ConcurrentHashMap k2_v = k1_k2V_map.get(key1); + if (k2_v != null) { + k2_v.remove(key2); + } + if (k2_v == null || k2_v.isEmpty()) { + k1_k2V_map.remove(key1); + } + } + + public void clear() { + if (k1_k2V_map.size() > 0) { + for (ConcurrentHashMap k2V_map : k1_k2V_map.values()) { + k2V_map.clear(); + } + k1_k2V_map.clear(); + } + } +} diff --git a/app/src/main/java/org/xutils/common/util/FileUtil.java b/app/src/main/java/org/xutils/common/util/FileUtil.java new file mode 100644 index 0000000..829988d --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/FileUtil.java @@ -0,0 +1,136 @@ +package org.xutils.common.util; + +import android.os.Environment; +import android.os.StatFs; + +import org.xutils.x; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +public class FileUtil { + + private FileUtil() { + } + + public static File getCacheDir(String dirName) { + File result = null; + if (isDiskAvailable()) { + File cacheDir = x.app().getExternalCacheDir(); + if (cacheDir != null) { + result = new File(cacheDir, dirName); + } + } + if (result == null) { + result = new File(x.app().getCacheDir(), dirName); + } + if (result.exists() || result.mkdirs()) { + return result; + } else { + return null; + } + } + + /** + * 检查磁盘空间是否大于10mb + * + * @return true 大于 + */ + public static boolean isDiskAvailable() { + long size = getDiskAvailableSize(); + return size > 10 * 1024 * 1024L; // > 10bm + } + + /** + * 获取磁盘可用空间 + * + * @return byte + */ + public static long getDiskAvailableSize() { + if (!existsSdcard()) return 0; + File path = Environment.getExternalStorageDirectory(); // 取得sdcard文件路径 + StatFs stat = new StatFs(path.getAbsolutePath()); + long blockSize = 0; + long availableBlocks = 0; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) { + blockSize = stat.getBlockSizeLong(); + availableBlocks = stat.getAvailableBlocksLong(); + } else { + blockSize = stat.getBlockSize(); + availableBlocks = stat.getAvailableBlocks(); + } + return availableBlocks * blockSize; + } + + public static Boolean existsSdcard() { + return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); + } + + public static long getFileOrDirSize(File file) { + if (!file.exists()) return 0; + if (!file.isDirectory()) return file.length(); + + long length = 0; + File[] list = file.listFiles(); + if (list != null) { // 文件夹被删除时, 子文件正在被写入, 文件属性异常返回null. + for (File item : list) { + length += getFileOrDirSize(item); + } + } + + return length; + } + + /** + * 复制文件到指定文件 + * + * @param fromPath 源文件 + * @param toPath 复制到的文件 + * @return true 成功,false 失败 + */ + public static boolean copy(String fromPath, String toPath) { + boolean result = false; + File from = new File(fromPath); + if (!from.exists()) { + return result; + } + + File toFile = new File(toPath); + IOUtil.deleteFileOrDir(toFile); + File toDir = toFile.getParentFile(); + if (toDir.exists() || toDir.mkdirs()) { + FileInputStream in = null; + FileOutputStream out = null; + try { + in = new FileInputStream(from); + out = new FileOutputStream(toFile); + IOUtil.copy(in, out); + result = true; + } catch (Throwable ex) { + LogUtil.d(ex.getMessage(), ex); + result = false; + } finally { + IOUtil.closeQuietly(in); + IOUtil.closeQuietly(out); + } + } + return result; + } + + public static boolean deleteFileOrDir(File path) { + if (path == null || !path.exists()) { + return true; + } + if (path.isFile()) { + return path.delete(); + } + File[] files = path.listFiles(); + if (files != null) { + for (File file : files) { + deleteFileOrDir(file); + } + } + return path.delete(); + } +} diff --git a/app/src/main/java/org/xutils/common/util/IOUtil.java b/app/src/main/java/org/xutils/common/util/IOUtil.java new file mode 100644 index 0000000..7d6b7b3 --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/IOUtil.java @@ -0,0 +1,127 @@ +package org.xutils.common.util; + +import android.database.Cursor; +import android.text.TextUtils; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; + +public class IOUtil { + + private IOUtil() { + } + + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (Throwable ex) { + LogUtil.d(ex.getMessage(), ex); + } + } + } + + public static void closeQuietly(Cursor cursor) { + if (cursor != null) { + try { + cursor.close(); + } catch (Throwable ex) { + LogUtil.d(ex.getMessage(), ex); + } + } + } + + public static byte[] readBytes(InputStream in) throws IOException { + if (!(in instanceof BufferedInputStream)) { + in = new BufferedInputStream(in); + } + ByteArrayOutputStream out = null; + try { + out = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); + } + return out.toByteArray(); + } finally { + closeQuietly(out); + } + } + + public static byte[] readBytes(InputStream in, long skip, int size) throws IOException { + byte[] result = null; + if (skip > 0) { + long skipped = 0; + while (skip > 0 && (skipped = in.skip(skip)) > 0) { + skip -= skipped; + } + } + result = new byte[size]; + for (int i = 0; i < size; i++) { + result[i] = (byte) in.read(); + } + return result; + } + + public static String readStr(InputStream in) throws IOException { + return readStr(in, "UTF-8"); + } + + public static String readStr(InputStream in, String charset) throws IOException { + if (TextUtils.isEmpty(charset)) charset = "UTF-8"; + + if (!(in instanceof BufferedInputStream)) { + in = new BufferedInputStream(in); + } + Reader reader = new InputStreamReader(in, charset); + StringBuilder sb = new StringBuilder(); + char[] buf = new char[1024]; + int len; + while ((len = reader.read(buf)) >= 0) { + sb.append(buf, 0, len); + } + return sb.toString(); + } + + public static void writeStr(OutputStream out, String str) throws IOException { + writeStr(out, str, "UTF-8"); + } + + public static void writeStr(OutputStream out, String str, String charset) throws IOException { + if (TextUtils.isEmpty(charset)) charset = "UTF-8"; + + Writer writer = new OutputStreamWriter(out, charset); + writer.write(str); + writer.flush(); + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + if (!(in instanceof BufferedInputStream)) { + in = new BufferedInputStream(in); + } + if (!(out instanceof BufferedOutputStream)) { + out = new BufferedOutputStream(out); + } + int len = 0; + byte[] buffer = new byte[1024]; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + out.flush(); + } + + public static boolean deleteFileOrDir(File path) { + return FileUtil.deleteFileOrDir(path); + } +} diff --git a/app/src/main/java/org/xutils/common/util/KeyValue.java b/app/src/main/java/org/xutils/common/util/KeyValue.java new file mode 100644 index 0000000..2cba986 --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/KeyValue.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.common.util; + +public class KeyValue { + public final String key; + public final Object value; + + public KeyValue(String key, Object value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public Object getValue() { + return value; + } + + /** + * 获取value的字符串值, 为null时返回空字符串 + */ + public String getValueStrOrEmpty() { + return value == null ? "" : value.toString(); + } + + /** + * 获取value的字符串值, 为null时返回null + */ + public String getValueStrOrNull() { + return value == null ? null : value.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + KeyValue keyValue = (KeyValue) o; + + return key == null ? keyValue.key == null : key.equals(keyValue.key); + + } + + @Override + public int hashCode() { + return key != null ? key.hashCode() : 0; + } + + @Override + public String toString() { + return "KeyValue{" + "key='" + key + '\'' + ", value=" + value + '}'; + } +} diff --git a/app/src/main/java/org/xutils/common/util/LogUtil.java b/app/src/main/java/org/xutils/common/util/LogUtil.java new file mode 100644 index 0000000..3914b0d --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/LogUtil.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.common.util; + +import android.text.TextUtils; +import android.util.Log; + +import org.xutils.x; + +import java.util.Locale; + +/** + * Log工具,类似android.util.Log。 + * tag自动产生,格式: customTagPrefix:className.methodName(L:lineNumber), + * customTagPrefix为空时只输出:className.methodName(L:lineNumber)。 + * Author: wyouflf + * Date: 13-7-24 + * Time: 下午12:23 + */ +public class LogUtil { + + public static String customTagPrefix = "x_log"; + + private LogUtil() { + } + + private static String generateTag() { + StackTraceElement caller = new Throwable().getStackTrace()[2]; + String tag = "%s.%s(L:%d)"; + String callerClazzName = caller.getClassName(); + callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1); + tag = String.format(Locale.getDefault(), tag, callerClazzName, caller.getMethodName(), caller.getLineNumber()); + tag = TextUtils.isEmpty(customTagPrefix) ? tag : customTagPrefix + ":" + tag; + return tag; + } + + public static void d(String content) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.d(tag, content); + } + + public static void d(String content, Throwable tr) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.d(tag, content, tr); + } + + public static void e(String content) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.e(tag, content); + } + + public static void e(String content, Throwable tr) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.e(tag, content, tr); + } + + public static void i(String content) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.i(tag, content); + } + + public static void i(String content, Throwable tr) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.i(tag, content, tr); + } + + public static void v(String content) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.v(tag, content); + } + + public static void v(String content, Throwable tr) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.v(tag, content, tr); + } + + public static void w(String content) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.w(tag, content); + } + + public static void w(String content, Throwable tr) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.w(tag, content, tr); + } + + public static void w(Throwable tr) { + if (!x.isDebug()) return; + String tag = generateTag(); + + Log.w(tag, tr); + } + + + public static void wtf(String content) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.wtf(tag, content); + } + + public static void wtf(String content, Throwable tr) { + if (!x.isDebug() || TextUtils.isEmpty(content)) return; + String tag = generateTag(); + + Log.wtf(tag, content, tr); + } + + public static void wtf(Throwable tr) { + if (!x.isDebug()) return; + String tag = generateTag(); + + Log.wtf(tag, tr); + } + +} diff --git a/app/src/main/java/org/xutils/common/util/MD5.java b/app/src/main/java/org/xutils/common/util/MD5.java new file mode 100644 index 0000000..224de76 --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/MD5.java @@ -0,0 +1,64 @@ +package org.xutils.common.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public final class MD5 { + + private MD5() { + } + + private static final char[] hexDigits = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + public static String toHexString(byte[] bytes) { + if (bytes == null) return ""; + StringBuilder hex = new StringBuilder(bytes.length * 2); + for (byte b : bytes) { + hex.append(hexDigits[(b >> 4) & 0x0F]); + hex.append(hexDigits[b & 0x0F]); + } + return hex.toString(); + } + + public static String md5(File file) throws IOException { + MessageDigest messagedigest = null; + FileInputStream in = null; + FileChannel ch = null; + byte[] encodeBytes = null; + try { + messagedigest = MessageDigest.getInstance("MD5"); + in = new FileInputStream(file); + ch = in.getChannel(); + MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); + messagedigest.update(byteBuffer); + encodeBytes = messagedigest.digest(); + } catch (NoSuchAlgorithmException neverHappened) { + throw new RuntimeException(neverHappened); + } finally { + IOUtil.closeQuietly(in); + IOUtil.closeQuietly(ch); + } + + return toHexString(encodeBytes); + } + + public static String md5(String string) { + byte[] encodeBytes = null; + try { + encodeBytes = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8")); + } catch (NoSuchAlgorithmException neverHappened) { + throw new RuntimeException(neverHappened); + } catch (UnsupportedEncodingException neverHappened) { + throw new RuntimeException(neverHappened); + } + + return toHexString(encodeBytes); + } +} diff --git a/app/src/main/java/org/xutils/common/util/ParameterizedTypeUtil.java b/app/src/main/java/org/xutils/common/util/ParameterizedTypeUtil.java new file mode 100644 index 0000000..f7ea273 --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/ParameterizedTypeUtil.java @@ -0,0 +1,97 @@ +package org.xutils.common.util; + +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; + +public class ParameterizedTypeUtil { + + private ParameterizedTypeUtil() { + } + + public static Type getParameterizedType( + + final Type ownerType, + final Class declaredClass, + int paramIndex) { + + Class clazz = null; + ParameterizedType pt = null; + Type[] ats = null; + TypeVariable[] tps = null; + if (ownerType instanceof ParameterizedType) { + pt = (ParameterizedType) ownerType; + clazz = (Class) pt.getRawType(); + ats = pt.getActualTypeArguments(); + tps = clazz.getTypeParameters(); + } else { + clazz = (Class) ownerType; + } + if (declaredClass == clazz) { + if (ats != null) { + return ats[paramIndex]; + } + return Object.class; + } + + Type[] types = clazz.getGenericInterfaces(); + if (types != null) { + for (int i = 0; i < types.length; i++) { + Type t = types[i]; + if (t instanceof ParameterizedType) { + Class cls = (Class) ((ParameterizedType) t).getRawType(); + if (declaredClass.isAssignableFrom(cls)) { + try { + return getTrueType(getParameterizedType(t, declaredClass, paramIndex), tps, ats); + } catch (Throwable ex) { + LogUtil.w(ex.getMessage(), ex); + } + } + } + } + } + + Class superClass = clazz.getSuperclass(); + if (superClass != null) { + if (declaredClass.isAssignableFrom(superClass)) { + return getTrueType( + getParameterizedType(clazz.getGenericSuperclass(), + declaredClass, paramIndex), tps, ats); + } + } + + throw new IllegalArgumentException("FindGenericType:" + ownerType + + ", declaredClass: " + declaredClass + ", index: " + paramIndex); + + } + + + private static Type getTrueType( + + Type type, + TypeVariable[] typeVariables, + Type[] actualTypes) { + + if (type instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) type; + String name = tv.getName(); + if (actualTypes != null) { + for (int i = 0; i < typeVariables.length; i++) { + if (name.equals(typeVariables[i].getName())) { + return actualTypes[i]; + } + } + } + return tv; + } else if (type instanceof GenericArrayType) { + Type ct = ((GenericArrayType) type).getGenericComponentType(); + if (ct instanceof Class) { + return Array.newInstance((Class) ct, 0).getClass(); + } + } + return type; + } + +} diff --git a/app/src/main/java/org/xutils/common/util/ProcessLock.java b/app/src/main/java/org/xutils/common/util/ProcessLock.java new file mode 100644 index 0000000..9d939fb --- /dev/null +++ b/app/src/main/java/org/xutils/common/util/ProcessLock.java @@ -0,0 +1,234 @@ +package org.xutils.common.util; + + +import android.content.Context; +import android.text.TextUtils; + +import org.xutils.x; + +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.text.DecimalFormat; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 进程间锁, 仅在同一个应用中有效. + */ +public final class ProcessLock implements Closeable { + + private final String mLockName; + private final FileLock mFileLock; + private final File mFile; + private final Closeable mStream; + private final boolean mWriteMode; + + private final static String LOCK_FILE_DIR = "process_lock"; + /** + * key1: lockName + * key2: fileLock.hashCode() + */ + private final static DoubleKeyValueMap LOCK_MAP = new DoubleKeyValueMap(); + + static { + File dir = x.app().getDir(LOCK_FILE_DIR, Context.MODE_PRIVATE); + IOUtil.deleteFileOrDir(dir); + } + + private ProcessLock(String lockName, File file, FileLock fileLock, Closeable stream, boolean writeMode) { + mLockName = lockName; + mFileLock = fileLock; + mFile = file; + mStream = stream; + mWriteMode = writeMode; + } + + /** + * 获取进程锁 + * + * @param lockName 锁的名称, 相同的名称被认为是同一个锁. + * @param writeMode 是否写入模式(支持读并发). + * @return null 或 进程锁, 如果锁已经被占用, 返回null. + */ + public static ProcessLock tryLock(final String lockName, final boolean writeMode) { + return tryLockInternal(lockName, customHash(lockName), writeMode); + } + + /** + * 获取进程锁 + * + * @param lockName 锁的名称, 相同的名称被认为是同一个锁. + * @param writeMode 是否写入模式(支持读并发). + * @param maxWaitTimeMillis 最大值 1000 * 60 + * @return null 或 进程锁, 如果锁已经被占用, 则在超时时间内继续尝试获取该锁. + */ + public static ProcessLock tryLock(final String lockName, final boolean writeMode, final long maxWaitTimeMillis) throws InterruptedException { + ProcessLock lock = null; + long expiryTime = System.currentTimeMillis() + maxWaitTimeMillis; + String hash = customHash(lockName); + synchronized (LOCK_MAP) { + while (System.currentTimeMillis() < expiryTime) { + lock = tryLockInternal(lockName, hash, writeMode); + if (lock != null) { + break; + } else { + try { + LOCK_MAP.wait(10); + } catch (InterruptedException iex) { + throw iex; + } catch (Throwable ignored) { + } + } + } + } + + return lock; + } + + /** + * 锁是否有效 + */ + public boolean isValid() { + return isValid(mFileLock); + } + + /** + * 释放锁 + */ + public void release() { + release(mLockName, mFileLock, mFile, mStream); + } + + /** + * 释放锁 + */ + @Override + public void close() throws IOException { + release(); + } + + private static boolean isValid(FileLock fileLock) { + return fileLock != null && fileLock.isValid(); + } + + private static void release(String lockName, FileLock fileLock, File file, Closeable stream) { + synchronized (LOCK_MAP) { + if (fileLock != null) { + try { + LOCK_MAP.remove(lockName, fileLock.hashCode()); + ConcurrentHashMap locks = LOCK_MAP.get(lockName); + if (locks == null || locks.isEmpty()) { + IOUtil.deleteFileOrDir(file); + } + + if (fileLock.channel().isOpen()) { + fileLock.release(); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } finally { + IOUtil.closeQuietly(fileLock.channel()); + } + } + + IOUtil.closeQuietly(stream); + + LOCK_MAP.notifyAll(); + } + } + + private final static DecimalFormat FORMAT = new DecimalFormat("0.##################"); + + // 取得字符串的自定义hash值, 尽量保证255字节内的hash不重复. + private static String customHash(String str) { + if (TextUtils.isEmpty(str)) return "0"; + double hash = 0.0; + byte[] bytes = str.getBytes(); + for (int i = 0; i < str.length(); i++) { + hash = (255.0 * hash + bytes[i]) * 0.005; + } + return FORMAT.format(hash); + } + + private static ProcessLock tryLockInternal(final String lockName, final String hash, final boolean writeMode) { + synchronized (LOCK_MAP) { + + ConcurrentHashMap locks = LOCK_MAP.get(lockName); + if (locks != null && !locks.isEmpty()) { + Iterator> itr = locks.entrySet().iterator(); + while (itr.hasNext()) { + Map.Entry entry = itr.next(); + ProcessLock value = entry.getValue(); + if (value != null) { + if (!value.isValid()) { + itr.remove(); + } else if (writeMode) { + return null; + } else if (value.mWriteMode) { + return null; + } + } else { + itr.remove(); + } + } + } + + FileChannel channel = null; + Closeable stream = null; + try { + File file = new File( + x.app().getDir(LOCK_FILE_DIR, Context.MODE_PRIVATE), + hash); + if (file.exists() || file.createNewFile()) { + + if (writeMode) { + FileOutputStream out = new FileOutputStream(file, false); + channel = out.getChannel(); + stream = out; + } else { + FileInputStream in = new FileInputStream(file); + channel = in.getChannel(); + stream = in; + } + if (channel != null) { + FileLock fileLock = channel.tryLock(0L, Long.MAX_VALUE, !writeMode); + if (isValid(fileLock)) { + ProcessLock result = new ProcessLock(lockName, file, fileLock, stream, writeMode); + LOCK_MAP.put(lockName, fileLock.hashCode(), result); + return result; + } else { + release(lockName, fileLock, file, stream); + } + } else { + throw new IOException("can not get file channel:" + file.getAbsolutePath()); + } + } + } catch (Throwable ex) { + LogUtil.d("tryLock: " + lockName + ", " + ex.getMessage()); + IOUtil.closeQuietly(stream); + IOUtil.closeQuietly(channel); + } + + LOCK_MAP.notifyAll(); + } + + return null; + } + + @Override + public String toString() { + return mLockName + ": " + mFile.getName(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + this.release(); + } +} diff --git a/app/src/main/java/org/xutils/config/DbConfigs.java b/app/src/main/java/org/xutils/config/DbConfigs.java new file mode 100644 index 0000000..e6453b8 --- /dev/null +++ b/app/src/main/java/org/xutils/config/DbConfigs.java @@ -0,0 +1,61 @@ +package org.xutils.config; + +import org.xutils.DbManager; +import org.xutils.common.util.LogUtil; +import org.xutils.ex.DbException; + +/** + * Created by wyouflf on 15/7/31. + * 全局db配置 + */ +public enum DbConfigs { + HTTP(new DbManager.DaoConfig() + .setDbName("xUtils_http_cache.db") + .setDbVersion(2) + .setDbOpenListener(new DbManager.DbOpenListener() { + @Override + public void onDbOpened(DbManager db) { + db.getDatabase().enableWriteAheadLogging(); + } + }) + .setDbUpgradeListener(new DbManager.DbUpgradeListener() { + @Override + public void onUpgrade(DbManager db, int oldVersion, int newVersion) { + try { + db.dropDb(); // 默认删除所有表 + } catch (DbException ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + })), + + COOKIE(new DbManager.DaoConfig() + .setDbName("xUtils_http_cookie.db") + .setDbVersion(1) + .setDbOpenListener(new DbManager.DbOpenListener() { + @Override + public void onDbOpened(DbManager db) { + db.getDatabase().enableWriteAheadLogging(); + } + }) + .setDbUpgradeListener(new DbManager.DbUpgradeListener() { + @Override + public void onUpgrade(DbManager db, int oldVersion, int newVersion) { + try { + db.dropDb(); // 默认删除所有表 + } catch (DbException ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + })); + + private DbManager.DaoConfig config; + + DbConfigs(DbManager.DaoConfig config) { + this.config = config; + } + + public DbManager.DaoConfig getConfig() { + return config; + } +} diff --git a/app/src/main/java/org/xutils/db/CursorUtils.java b/app/src/main/java/org/xutils/db/CursorUtils.java new file mode 100644 index 0000000..84296df --- /dev/null +++ b/app/src/main/java/org/xutils/db/CursorUtils.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db; + +import android.database.Cursor; + +import org.xutils.db.table.ColumnEntity; +import org.xutils.db.table.DbModel; +import org.xutils.db.table.TableEntity; + +import java.util.HashMap; + +/*package*/ final class CursorUtils { + + public static T getEntity(TableEntity table, final Cursor cursor) throws Throwable { + T entity = table.createEntity(); + HashMap columnMap = table.getColumnMap(); + int columnCount = cursor.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + String columnName = cursor.getColumnName(i); + ColumnEntity column = columnMap.get(columnName); + if (column != null) { + column.setValueFromCursor(entity, cursor, i); + } + } + return entity; + } + + public static DbModel getDbModel(final Cursor cursor) { + DbModel result = new DbModel(); + int columnCount = cursor.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + result.add(cursor.getColumnName(i), cursor.getString(i)); + } + return result; + } +} diff --git a/app/src/main/java/org/xutils/db/DbManagerImpl.java b/app/src/main/java/org/xutils/db/DbManagerImpl.java new file mode 100644 index 0000000..7266d85 --- /dev/null +++ b/app/src/main/java/org/xutils/db/DbManagerImpl.java @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; +import android.os.Build; + +import org.xutils.DbManager; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.KeyValue; +import org.xutils.common.util.LogUtil; +import org.xutils.db.sqlite.SqlInfo; +import org.xutils.db.sqlite.SqlInfoBuilder; +import org.xutils.db.sqlite.WhereBuilder; +import org.xutils.db.table.ColumnEntity; +import org.xutils.db.table.DbBase; +import org.xutils.db.table.DbModel; +import org.xutils.db.table.TableEntity; +import org.xutils.ex.DbException; +import org.xutils.x; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class DbManagerImpl extends DbBase { + + //*************************************** create instance **************************************************** + + /** + * key: dbName + */ + private final static HashMap DAO_MAP = new HashMap(); + + private SQLiteDatabase database; + private DaoConfig daoConfig; + private boolean allowTransaction; + + private DbManagerImpl(DaoConfig config) throws DbException { + if (config == null) { + throw new IllegalArgumentException("daoConfig may not be null"); + } + + this.daoConfig = config; + this.allowTransaction = config.isAllowTransaction(); + try { + this.database = openOrCreateDatabase(config); + DbOpenListener dbOpenListener = config.getDbOpenListener(); + if (dbOpenListener != null) { + dbOpenListener.onDbOpened(this); + } + } catch (DbException ex) { + IOUtil.closeQuietly(this.database); + throw ex; + } catch (Throwable ex) { + IOUtil.closeQuietly(this.database); + throw new DbException(ex.getMessage(), ex); + } + } + + public synchronized static DbManager getInstance(DaoConfig daoConfig) throws DbException { + + if (daoConfig == null) {//使用默认配置 + daoConfig = new DaoConfig(); + } + + DbManagerImpl dao = DAO_MAP.get(daoConfig); + if (dao == null) { + dao = new DbManagerImpl(daoConfig); + DAO_MAP.put(daoConfig, dao); + } else { + dao.daoConfig = daoConfig; + } + + // update the database if needed + SQLiteDatabase database = dao.database; + int oldVersion = database.getVersion(); + int newVersion = daoConfig.getDbVersion(); + if (oldVersion != newVersion) { + if (oldVersion != 0) { + DbUpgradeListener upgradeListener = daoConfig.getDbUpgradeListener(); + if (upgradeListener != null) { + upgradeListener.onUpgrade(dao, oldVersion, newVersion); + } else { + dao.dropDb(); + } + } + database.setVersion(newVersion); + } + + return dao; + } + + @Override + public SQLiteDatabase getDatabase() { + return database; + } + + @Override + public DaoConfig getDaoConfig() { + return daoConfig; + } + + //*********************************************** operations ******************************************************** + + @Override + public void saveOrUpdate(Object entity) throws DbException { + try { + beginTransaction(); + + if (entity instanceof List) { + List entities = (List) entity; + if (entities.isEmpty()) return; + TableEntity table = this.getTable(entities.get(0).getClass()); + table.createTableIfNotExists(); + for (Object item : entities) { + saveOrUpdateWithoutTransaction(table, item); + } + } else { + TableEntity table = this.getTable(entity.getClass()); + table.createTableIfNotExists(); + saveOrUpdateWithoutTransaction(table, entity); + } + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + } + + @Override + public void replace(Object entity) throws DbException { + try { + beginTransaction(); + + if (entity instanceof List) { + List entities = (List) entity; + if (entities.isEmpty()) return; + TableEntity table = this.getTable(entities.get(0).getClass()); + table.createTableIfNotExists(); + for (Object item : entities) { + execNonQuery(SqlInfoBuilder.buildReplaceSqlInfo(table, item)); + } + } else { + TableEntity table = this.getTable(entity.getClass()); + table.createTableIfNotExists(); + execNonQuery(SqlInfoBuilder.buildReplaceSqlInfo(table, entity)); + } + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + } + + @Override + public void save(Object entity) throws DbException { + try { + beginTransaction(); + + if (entity instanceof List) { + List entities = (List) entity; + if (entities.isEmpty()) return; + TableEntity table = this.getTable(entities.get(0).getClass()); + table.createTableIfNotExists(); + for (Object item : entities) { + execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(table, item)); + } + } else { + TableEntity table = this.getTable(entity.getClass()); + table.createTableIfNotExists(); + execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(table, entity)); + } + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + } + + @Override + public boolean saveBindingId(Object entity) throws DbException { + boolean result = false; + try { + beginTransaction(); + + if (entity instanceof List) { + List entities = (List) entity; + if (entities.isEmpty()) return false; + TableEntity table = this.getTable(entities.get(0).getClass()); + table.createTableIfNotExists(); + for (Object item : entities) { + if (!saveBindingIdWithoutTransaction(table, item)) { + throw new DbException("saveBindingId error, transaction will not commit!"); + } + } + } else { + TableEntity table = this.getTable(entity.getClass()); + table.createTableIfNotExists(); + result = saveBindingIdWithoutTransaction(table, entity); + } + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + return result; + } + + @Override + public void deleteById(Class entityType, Object idValue) throws DbException { + TableEntity table = this.getTable(entityType); + if (!table.tableIsExists()) return; + try { + beginTransaction(); + + execNonQuery(SqlInfoBuilder.buildDeleteSqlInfoById(table, idValue)); + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + } + + @Override + public void delete(Object entity) throws DbException { + try { + beginTransaction(); + + if (entity instanceof List) { + List entities = (List) entity; + if (entities.isEmpty()) return; + TableEntity table = this.getTable(entities.get(0).getClass()); + if (!table.tableIsExists()) return; + for (Object item : entities) { + execNonQuery(SqlInfoBuilder.buildDeleteSqlInfo(table, item)); + } + } else { + TableEntity table = this.getTable(entity.getClass()); + if (!table.tableIsExists()) return; + execNonQuery(SqlInfoBuilder.buildDeleteSqlInfo(table, entity)); + } + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + } + + @Override + public void delete(Class entityType) throws DbException { + delete(entityType, null); + } + + @Override + public int delete(Class entityType, WhereBuilder whereBuilder) throws DbException { + TableEntity table = this.getTable(entityType); + if (!table.tableIsExists()) return 0; + int result = 0; + try { + beginTransaction(); + + result = executeUpdateDelete(SqlInfoBuilder.buildDeleteSqlInfo(table, whereBuilder)); + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + return result; + } + + @Override + public void update(Object entity, String... updateColumnNames) throws DbException { + try { + beginTransaction(); + + if (entity instanceof List) { + List entities = (List) entity; + if (entities.isEmpty()) return; + TableEntity table = this.getTable(entities.get(0).getClass()); + if (!table.tableIsExists()) return; + for (Object item : entities) { + execNonQuery(SqlInfoBuilder.buildUpdateSqlInfo(table, item, updateColumnNames)); + } + } else { + TableEntity table = this.getTable(entity.getClass()); + if (!table.tableIsExists()) return; + execNonQuery(SqlInfoBuilder.buildUpdateSqlInfo(table, entity, updateColumnNames)); + } + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + } + + @Override + public int update(Class entityType, WhereBuilder whereBuilder, KeyValue... nameValuePairs) throws DbException { + TableEntity table = this.getTable(entityType); + if (!table.tableIsExists()) return 0; + + int result = 0; + try { + beginTransaction(); + + result = executeUpdateDelete(SqlInfoBuilder.buildUpdateSqlInfo(table, whereBuilder, nameValuePairs)); + + setTransactionSuccessful(); + } finally { + endTransaction(); + } + + return result; + } + + @Override + public T findById(Class entityType, Object idValue) throws DbException { + TableEntity table = this.getTable(entityType); + if (!table.tableIsExists()) return null; + + Selector selector = Selector.from(table).where(table.getId().getName(), "=", idValue); + String sql = selector.limit(1).toString(); + Cursor cursor = execQuery(sql); + if (cursor != null) { + try { + if (cursor.moveToNext()) { + return CursorUtils.getEntity(table, cursor); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + return null; + } + + @Override + public T findFirst(Class entityType) throws DbException { + return this.selector(entityType).findFirst(); + } + + @Override + public List findAll(Class entityType) throws DbException { + return this.selector(entityType).findAll(); + } + + @Override + public Selector selector(Class entityType) throws DbException { + return Selector.from(this.getTable(entityType)); + } + + @Override + public DbModel findDbModelFirst(SqlInfo sqlInfo) throws DbException { + Cursor cursor = execQuery(sqlInfo); + if (cursor != null) { + try { + if (cursor.moveToNext()) { + return CursorUtils.getDbModel(cursor); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + return null; + } + + @Override + public List findDbModelAll(SqlInfo sqlInfo) throws DbException { + List dbModelList = new ArrayList(); + + Cursor cursor = execQuery(sqlInfo); + if (cursor != null) { + try { + while (cursor.moveToNext()) { + dbModelList.add(CursorUtils.getDbModel(cursor)); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + return dbModelList; + } + + //******************************************** config ****************************************************** + + private SQLiteDatabase openOrCreateDatabase(DaoConfig config) { + SQLiteDatabase result = null; + + File dbDir = config.getDbDir(); + if (dbDir != null && (dbDir.exists() || dbDir.mkdirs())) { + File dbFile = new File(dbDir, config.getDbName()); + result = SQLiteDatabase.openOrCreateDatabase(dbFile, null); + } else { + result = x.app().openOrCreateDatabase(config.getDbName(), 0, null); + } + return result; + } + + //***************************** private operations with out transaction ***************************** + private void saveOrUpdateWithoutTransaction(TableEntity table, Object entity) throws DbException { + ColumnEntity id = table.getId(); + if (id.isAutoId()) { + if (id.getColumnValue(entity) != null) { + execNonQuery(SqlInfoBuilder.buildUpdateSqlInfo(table, entity)); + } else { + saveBindingIdWithoutTransaction(table, entity); + } + } else { + execNonQuery(SqlInfoBuilder.buildReplaceSqlInfo(table, entity)); + } + } + + private boolean saveBindingIdWithoutTransaction(TableEntity table, Object entity) throws DbException { + ColumnEntity id = table.getId(); + if (id.isAutoId()) { + execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(table, entity)); + long idValue = getLastAutoIncrementId(table.getName()); + if (idValue == -1) { + return false; + } + id.setAutoIdValue(entity, idValue); + return true; + } else { + execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(table, entity)); + return true; + } + } + + //************************************************ tools *********************************** + + private long getLastAutoIncrementId(String tableName) throws DbException { + long id = -1; + Cursor cursor = execQuery("SELECT seq FROM sqlite_sequence WHERE name='" + tableName + "' LIMIT 1"); + if (cursor != null) { + try { + if (cursor.moveToNext()) { + id = cursor.getLong(0); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + return id; + } + + /** + * 关闭数据库. + * 同一个库的是单实例的, 尽量不要调用这个方法, 会自动释放. + */ + @Override + public void close() throws IOException { + if (DAO_MAP.containsKey(daoConfig)) { + DAO_MAP.remove(daoConfig); + this.database.close(); + } + } + + ///////////////////////////////////// exec sql ///////////////////////////////////////////////////// + + private void beginTransaction() { + if (allowTransaction) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && database.isWriteAheadLoggingEnabled()) { + database.beginTransactionNonExclusive(); + } else { + database.beginTransaction(); + } + } + } + + private void setTransactionSuccessful() { + if (allowTransaction) { + database.setTransactionSuccessful(); + } + } + + private void endTransaction() { + if (allowTransaction) { + database.endTransaction(); + } + } + + + @Override + public int executeUpdateDelete(SqlInfo sqlInfo) throws DbException { + SQLiteStatement statement = null; + try { + statement = sqlInfo.buildStatement(database); + return statement.executeUpdateDelete(); + } catch (Throwable e) { + throw new DbException(e); + } finally { + if (statement != null) { + try { + statement.releaseReference(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + + @Override + public int executeUpdateDelete(String sql) throws DbException { + SQLiteStatement statement = null; + try { + statement = database.compileStatement(sql); + return statement.executeUpdateDelete(); + } catch (Throwable e) { + throw new DbException(e); + } finally { + if (statement != null) { + try { + statement.releaseReference(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + + @Override + public void execNonQuery(SqlInfo sqlInfo) throws DbException { + SQLiteStatement statement = null; + try { + statement = sqlInfo.buildStatement(database); + statement.execute(); + } catch (Throwable e) { + throw new DbException(e); + } finally { + if (statement != null) { + try { + statement.releaseReference(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + + @Override + public void execNonQuery(String sql) throws DbException { + try { + database.execSQL(sql); + } catch (Throwable e) { + throw new DbException(e); + } + } + + @Override + public Cursor execQuery(SqlInfo sqlInfo) throws DbException { + try { + return database.rawQuery(sqlInfo.getSql(), sqlInfo.getBindArgsAsStrArray()); + } catch (Throwable e) { + throw new DbException(e); + } + } + + @Override + public Cursor execQuery(String sql) throws DbException { + try { + return database.rawQuery(sql, null); + } catch (Throwable e) { + throw new DbException(e); + } + } + +} diff --git a/app/src/main/java/org/xutils/db/DbModelSelector.java b/app/src/main/java/org/xutils/db/DbModelSelector.java new file mode 100644 index 0000000..0fe2003 --- /dev/null +++ b/app/src/main/java/org/xutils/db/DbModelSelector.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db; + +import android.database.Cursor; +import android.text.TextUtils; + +import org.xutils.common.util.IOUtil; +import org.xutils.db.sqlite.WhereBuilder; +import org.xutils.db.table.DbModel; +import org.xutils.db.table.TableEntity; +import org.xutils.ex.DbException; + +import java.util.ArrayList; +import java.util.List; + +/** + * Author: wyouflf + * Date: 13-8-10 + * Time: 下午2:15 + */ +public final class DbModelSelector { + + private String[] columnExpressions; + private String groupByColumnName; + private WhereBuilder having; + + private Selector selector; + + private DbModelSelector(TableEntity table) { + selector = Selector.from(table); + } + + protected DbModelSelector(Selector selector, String groupByColumnName) { + this.selector = selector; + this.groupByColumnName = groupByColumnName; + } + + protected DbModelSelector(Selector selector, String[] columnExpressions) { + this.selector = selector; + this.columnExpressions = columnExpressions; + } + + /*package*/ + static DbModelSelector from(TableEntity table) { + return new DbModelSelector(table); + } + + public DbModelSelector where(WhereBuilder whereBuilder) { + selector.where(whereBuilder); + return this; + } + + public DbModelSelector where(String columnName, String op, Object value) { + selector.where(columnName, op, value); + return this; + } + + public DbModelSelector and(String columnName, String op, Object value) { + selector.and(columnName, op, value); + return this; + } + + public DbModelSelector and(WhereBuilder where) { + selector.and(where); + return this; + } + + public DbModelSelector or(String columnName, String op, Object value) { + selector.or(columnName, op, value); + return this; + } + + public DbModelSelector or(WhereBuilder where) { + selector.or(where); + return this; + } + + public DbModelSelector expr(String expr) { + selector.expr(expr); + return this; + } + + public DbModelSelector groupBy(String columnName) { + this.groupByColumnName = columnName; + return this; + } + + public DbModelSelector having(WhereBuilder whereBuilder) { + this.having = whereBuilder; + return this; + } + + public DbModelSelector select(String... columnExpressions) { + this.columnExpressions = columnExpressions; + return this; + } + + /** + * 排序条件, 默认ASC + */ + public DbModelSelector orderBy(String columnName) { + selector.orderBy(columnName); + return this; + } + + /** + * 排序条件, 默认ASC + */ + public DbModelSelector orderBy(String columnName, boolean desc) { + selector.orderBy(columnName, desc); + return this; + } + + public DbModelSelector limit(int limit) { + selector.limit(limit); + return this; + } + + public DbModelSelector offset(int offset) { + selector.offset(offset); + return this; + } + + public TableEntity getTable() { + return selector.getTable(); + } + + public DbModel findFirst() throws DbException { + TableEntity table = selector.getTable(); + if (!table.tableIsExists()) return null; + + this.limit(1); + Cursor cursor = table.getDb().execQuery(this.toString()); + if (cursor != null) { + try { + if (cursor.moveToNext()) { + return CursorUtils.getDbModel(cursor); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + return null; + } + + public List findAll() throws DbException { + TableEntity table = selector.getTable(); + if (!table.tableIsExists()) return null; + + List result = null; + + Cursor cursor = table.getDb().execQuery(this.toString()); + if (cursor != null) { + try { + result = new ArrayList(); + while (cursor.moveToNext()) { + DbModel entity = CursorUtils.getDbModel(cursor); + result.add(entity); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + return result; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("SELECT "); + if (columnExpressions != null && columnExpressions.length > 0) { + for (String columnExpression : columnExpressions) { + result.append(columnExpression); + result.append(","); + } + result.deleteCharAt(result.length() - 1); + } else { + if (!TextUtils.isEmpty(groupByColumnName)) { + result.append(groupByColumnName); + } else { + result.append("*"); + } + } + result.append(" FROM ").append("\"").append(selector.getTable().getName()).append("\""); + WhereBuilder whereBuilder = selector.getWhereBuilder(); + if (whereBuilder != null && whereBuilder.getWhereItemSize() > 0) { + result.append(" WHERE ").append(whereBuilder.toString()); + } + if (!TextUtils.isEmpty(groupByColumnName)) { + result.append(" GROUP BY ").append("\"").append(groupByColumnName).append("\""); + if (having != null && having.getWhereItemSize() > 0) { + result.append(" HAVING ").append(having.toString()); + } + } + List orderByList = selector.getOrderByList(); + if (orderByList != null && orderByList.size() > 0) { + result.append(" ORDER BY "); + for (Selector.OrderBy orderBy : orderByList) { + result.append(orderBy.toString()).append(','); + } + result.deleteCharAt(result.length() - 1); + } + if (selector.getLimit() > 0) { + result.append(" LIMIT ").append(selector.getLimit()); + result.append(" OFFSET ").append(selector.getOffset()); + } + return result.toString(); + } +} diff --git a/app/src/main/java/org/xutils/db/Selector.java b/app/src/main/java/org/xutils/db/Selector.java new file mode 100644 index 0000000..95879fc --- /dev/null +++ b/app/src/main/java/org/xutils/db/Selector.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db; + +import android.database.Cursor; + +import org.xutils.common.util.IOUtil; +import org.xutils.db.sqlite.WhereBuilder; +import org.xutils.db.table.DbModel; +import org.xutils.db.table.TableEntity; +import org.xutils.ex.DbException; + +import java.util.ArrayList; +import java.util.List; + +/** + * Author: wyouflf + * Date: 13-8-9 + * Time: 下午10:19 + */ +public final class Selector { + + private final TableEntity table; + + private WhereBuilder whereBuilder; + private List orderByList; + private int limit = 0; + private int offset = 0; + + private Selector(TableEntity table) { + this.table = table; + } + + /*package*/ + static Selector from(TableEntity table) { + return new Selector(table); + } + + public Selector where(WhereBuilder whereBuilder) { + this.whereBuilder = whereBuilder; + return this; + } + + public Selector where(String columnName, String op, Object value) { + this.whereBuilder = WhereBuilder.b(columnName, op, value); + return this; + } + + public Selector and(String columnName, String op, Object value) { + this.whereBuilder.and(columnName, op, value); + return this; + } + + public Selector and(WhereBuilder where) { + this.whereBuilder.and(where); + return this; + } + + public Selector or(String columnName, String op, Object value) { + this.whereBuilder.or(columnName, op, value); + return this; + } + + public Selector or(WhereBuilder where) { + this.whereBuilder.or(where); + return this; + } + + public Selector expr(String expr) { + if (this.whereBuilder == null) { + this.whereBuilder = WhereBuilder.b(); + } + this.whereBuilder.expr(expr); + return this; + } + + public DbModelSelector groupBy(String columnName) { + return new DbModelSelector(this, columnName); + } + + public DbModelSelector select(String... columnExpressions) { + return new DbModelSelector(this, columnExpressions); + } + + /** + * 排序条件, 默认ASC + */ + public Selector orderBy(String columnName) { + if (orderByList == null) { + orderByList = new ArrayList(5); + } + orderByList.add(new OrderBy(columnName)); + return this; + } + + /** + * 排序条件, 默认ASC + */ + public Selector orderBy(String columnName, boolean desc) { + if (orderByList == null) { + orderByList = new ArrayList(5); + } + orderByList.add(new OrderBy(columnName, desc)); + return this; + } + + public Selector limit(int limit) { + this.limit = limit; + return this; + } + + public Selector offset(int offset) { + this.offset = offset; + return this; + } + + public TableEntity getTable() { + return table; + } + + public WhereBuilder getWhereBuilder() { + return whereBuilder; + } + + public List getOrderByList() { + return orderByList; + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + public T findFirst() throws DbException { + if (!table.tableIsExists()) return null; + + this.limit(1); + Cursor cursor = table.getDb().execQuery(this.toString()); + if (cursor != null) { + try { + if (cursor.moveToNext()) { + return CursorUtils.getEntity(table, cursor); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + return null; + } + + public List findAll() throws DbException { + if (!table.tableIsExists()) return null; + + List result = null; + Cursor cursor = table.getDb().execQuery(this.toString()); + if (cursor != null) { + try { + result = new ArrayList(); + while (cursor.moveToNext()) { + T entity = CursorUtils.getEntity(table, cursor); + result.add(entity); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + return result; + } + + public long count() throws DbException { + if (!table.tableIsExists()) return 0; + + DbModelSelector dmSelector = this.select("count(\"" + table.getId().getName() + "\") as count"); + DbModel firstModel = dmSelector.findFirst(); + if (firstModel != null) { + return firstModel.getLong("count", 0); + } + return 0; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("SELECT "); + result.append("*"); + result.append(" FROM ").append("\"").append(table.getName()).append("\""); + if (whereBuilder != null && whereBuilder.getWhereItemSize() > 0) { + result.append(" WHERE ").append(whereBuilder.toString()); + } + if (orderByList != null && orderByList.size() > 0) { + result.append(" ORDER BY "); + for (OrderBy orderBy : orderByList) { + result.append(orderBy.toString()).append(','); + } + result.deleteCharAt(result.length() - 1); + } + if (limit > 0) { + result.append(" LIMIT ").append(limit); + result.append(" OFFSET ").append(offset); + } + return result.toString(); + } + + public static class OrderBy { + private String columnName; + private boolean desc; + + /** + * 排序条件, 默认ASC + */ + public OrderBy(String columnName) { + this.columnName = columnName; + } + + /** + * 排序条件, 默认ASC + */ + public OrderBy(String columnName, boolean desc) { + this.columnName = columnName; + this.desc = desc; + } + + @Override + public String toString() { + return "\"" + columnName + "\"" + (desc ? " DESC" : " ASC"); + } + } +} diff --git a/app/src/main/java/org/xutils/db/annotation/Column.java b/app/src/main/java/org/xutils/db/annotation/Column.java new file mode 100644 index 0000000..b36f28d --- /dev/null +++ b/app/src/main/java/org/xutils/db/annotation/Column.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Column { + + String name(); + + String property() default ""; + + boolean isId() default false; + + boolean autoGen() default true; +} diff --git a/app/src/main/java/org/xutils/db/annotation/Table.java b/app/src/main/java/org/xutils/db/annotation/Table.java new file mode 100644 index 0000000..0189dba --- /dev/null +++ b/app/src/main/java/org/xutils/db/annotation/Table.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Table { + + String name(); + + String onCreated() default ""; +} \ No newline at end of file diff --git a/app/src/main/java/org/xutils/db/converter/BooleanColumnConverter.java b/app/src/main/java/org/xutils/db/converter/BooleanColumnConverter.java new file mode 100644 index 0000000..cf3f5df --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/BooleanColumnConverter.java @@ -0,0 +1,28 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class BooleanColumnConverter implements ColumnConverter { + @Override + public Boolean getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : cursor.getInt(index) == 1; + } + + @Override + public Object fieldValue2DbValue(Boolean fieldValue) { + if (fieldValue == null) return null; + return fieldValue ? 1 : 0; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.INTEGER; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/ByteArrayColumnConverter.java b/app/src/main/java/org/xutils/db/converter/ByteArrayColumnConverter.java new file mode 100644 index 0000000..f9de5a0 --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/ByteArrayColumnConverter.java @@ -0,0 +1,27 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class ByteArrayColumnConverter implements ColumnConverter { + @Override + public byte[] getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : cursor.getBlob(index); + } + + @Override + public Object fieldValue2DbValue(byte[] fieldValue) { + return fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.BLOB; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/ByteColumnConverter.java b/app/src/main/java/org/xutils/db/converter/ByteColumnConverter.java new file mode 100644 index 0000000..e574bec --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/ByteColumnConverter.java @@ -0,0 +1,27 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class ByteColumnConverter implements ColumnConverter { + @Override + public Byte getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : (byte) cursor.getInt(index); + } + + @Override + public Object fieldValue2DbValue(Byte fieldValue) { + return fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.INTEGER; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/CharColumnConverter.java b/app/src/main/java/org/xutils/db/converter/CharColumnConverter.java new file mode 100644 index 0000000..4d39523 --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/CharColumnConverter.java @@ -0,0 +1,28 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class CharColumnConverter implements ColumnConverter { + @Override + public Character getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : (char) cursor.getInt(index); + } + + @Override + public Object fieldValue2DbValue(Character fieldValue) { + if (fieldValue == null) return null; + return (int) fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.INTEGER; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/ColumnConverter.java b/app/src/main/java/org/xutils/db/converter/ColumnConverter.java new file mode 100644 index 0000000..9b6b0ec --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/ColumnConverter.java @@ -0,0 +1,19 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午8:57 + */ +public interface ColumnConverter { + + T getFieldValue(final Cursor cursor, int index); + + Object fieldValue2DbValue(T fieldValue); + + ColumnDbType getColumnDbType(); +} diff --git a/app/src/main/java/org/xutils/db/converter/ColumnConverterFactory.java b/app/src/main/java/org/xutils/db/converter/ColumnConverterFactory.java new file mode 100644 index 0000000..68dc20a --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/ColumnConverterFactory.java @@ -0,0 +1,108 @@ +package org.xutils.db.converter; + +import org.xutils.common.util.LogUtil; + +import java.util.Date; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:27 + */ +public final class ColumnConverterFactory { + + private ColumnConverterFactory() { + } + + public static ColumnConverter getColumnConverter(Class columnType) { + ColumnConverter result = null; + if (columnType_columnConverter_map.containsKey(columnType.getName())) { + result = columnType_columnConverter_map.get(columnType.getName()); + } else if (ColumnConverter.class.isAssignableFrom(columnType)) { + try { + ColumnConverter columnConverter = (ColumnConverter) columnType.newInstance(); + columnType_columnConverter_map.put(columnType.getName(), columnConverter); + result = columnConverter; + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + if (result == null) { + throw new RuntimeException("Database Column Not Support: " + columnType.getName() + + ", please impl ColumnConverter or use ColumnConverterFactory#registerColumnConverter(...)"); + } + + return result; + } + + public static void registerColumnConverter(Class columnType, ColumnConverter columnConverter) { + columnType_columnConverter_map.put(columnType.getName(), columnConverter); + } + + public static boolean isSupportColumnConverter(Class columnType) { + if (columnType_columnConverter_map.containsKey(columnType.getName())) { + return true; + } else if (ColumnConverter.class.isAssignableFrom(columnType)) { + try { + ColumnConverter columnConverter = (ColumnConverter) columnType.newInstance(); + columnType_columnConverter_map.put(columnType.getName(), columnConverter); + return true; + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + return false; + } + + private static final ConcurrentHashMap columnType_columnConverter_map; + + static { + columnType_columnConverter_map = new ConcurrentHashMap(); + + BooleanColumnConverter booleanColumnConverter = new BooleanColumnConverter(); + columnType_columnConverter_map.put(boolean.class.getName(), booleanColumnConverter); + columnType_columnConverter_map.put(Boolean.class.getName(), booleanColumnConverter); + + ByteArrayColumnConverter byteArrayColumnConverter = new ByteArrayColumnConverter(); + columnType_columnConverter_map.put(byte[].class.getName(), byteArrayColumnConverter); + + ByteColumnConverter byteColumnConverter = new ByteColumnConverter(); + columnType_columnConverter_map.put(byte.class.getName(), byteColumnConverter); + columnType_columnConverter_map.put(Byte.class.getName(), byteColumnConverter); + + CharColumnConverter charColumnConverter = new CharColumnConverter(); + columnType_columnConverter_map.put(char.class.getName(), charColumnConverter); + columnType_columnConverter_map.put(Character.class.getName(), charColumnConverter); + + DateColumnConverter dateColumnConverter = new DateColumnConverter(); + columnType_columnConverter_map.put(Date.class.getName(), dateColumnConverter); + + DoubleColumnConverter doubleColumnConverter = new DoubleColumnConverter(); + columnType_columnConverter_map.put(double.class.getName(), doubleColumnConverter); + columnType_columnConverter_map.put(Double.class.getName(), doubleColumnConverter); + + FloatColumnConverter floatColumnConverter = new FloatColumnConverter(); + columnType_columnConverter_map.put(float.class.getName(), floatColumnConverter); + columnType_columnConverter_map.put(Float.class.getName(), floatColumnConverter); + + IntegerColumnConverter integerColumnConverter = new IntegerColumnConverter(); + columnType_columnConverter_map.put(int.class.getName(), integerColumnConverter); + columnType_columnConverter_map.put(Integer.class.getName(), integerColumnConverter); + + LongColumnConverter longColumnConverter = new LongColumnConverter(); + columnType_columnConverter_map.put(long.class.getName(), longColumnConverter); + columnType_columnConverter_map.put(Long.class.getName(), longColumnConverter); + + ShortColumnConverter shortColumnConverter = new ShortColumnConverter(); + columnType_columnConverter_map.put(short.class.getName(), shortColumnConverter); + columnType_columnConverter_map.put(Short.class.getName(), shortColumnConverter); + + SqlDateColumnConverter sqlDateColumnConverter = new SqlDateColumnConverter(); + columnType_columnConverter_map.put(java.sql.Date.class.getName(), sqlDateColumnConverter); + + StringColumnConverter stringColumnConverter = new StringColumnConverter(); + columnType_columnConverter_map.put(String.class.getName(), stringColumnConverter); + } +} diff --git a/app/src/main/java/org/xutils/db/converter/DateColumnConverter.java b/app/src/main/java/org/xutils/db/converter/DateColumnConverter.java new file mode 100644 index 0000000..3bc1dfa --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/DateColumnConverter.java @@ -0,0 +1,30 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +import java.util.Date; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class DateColumnConverter implements ColumnConverter { + @Override + public Date getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : new Date(cursor.getLong(index)); + } + + @Override + public Object fieldValue2DbValue(Date fieldValue) { + if (fieldValue == null) return null; + return fieldValue.getTime(); + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.INTEGER; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/DoubleColumnConverter.java b/app/src/main/java/org/xutils/db/converter/DoubleColumnConverter.java new file mode 100644 index 0000000..13e5434 --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/DoubleColumnConverter.java @@ -0,0 +1,27 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class DoubleColumnConverter implements ColumnConverter { + @Override + public Double getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : cursor.getDouble(index); + } + + @Override + public Object fieldValue2DbValue(Double fieldValue) { + return fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.REAL; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/FloatColumnConverter.java b/app/src/main/java/org/xutils/db/converter/FloatColumnConverter.java new file mode 100644 index 0000000..884c4b8 --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/FloatColumnConverter.java @@ -0,0 +1,27 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class FloatColumnConverter implements ColumnConverter { + @Override + public Float getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : cursor.getFloat(index); + } + + @Override + public Object fieldValue2DbValue(Float fieldValue) { + return fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.REAL; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/IntegerColumnConverter.java b/app/src/main/java/org/xutils/db/converter/IntegerColumnConverter.java new file mode 100644 index 0000000..c3d684b --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/IntegerColumnConverter.java @@ -0,0 +1,27 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class IntegerColumnConverter implements ColumnConverter { + @Override + public Integer getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : cursor.getInt(index); + } + + @Override + public Object fieldValue2DbValue(Integer fieldValue) { + return fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.INTEGER; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/LongColumnConverter.java b/app/src/main/java/org/xutils/db/converter/LongColumnConverter.java new file mode 100644 index 0000000..a4a760e --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/LongColumnConverter.java @@ -0,0 +1,27 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class LongColumnConverter implements ColumnConverter { + @Override + public Long getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : cursor.getLong(index); + } + + @Override + public Object fieldValue2DbValue(Long fieldValue) { + return fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.INTEGER; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/ShortColumnConverter.java b/app/src/main/java/org/xutils/db/converter/ShortColumnConverter.java new file mode 100644 index 0000000..86bf131 --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/ShortColumnConverter.java @@ -0,0 +1,27 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class ShortColumnConverter implements ColumnConverter { + @Override + public Short getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : cursor.getShort(index); + } + + @Override + public Object fieldValue2DbValue(Short fieldValue) { + return fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.INTEGER; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/SqlDateColumnConverter.java b/app/src/main/java/org/xutils/db/converter/SqlDateColumnConverter.java new file mode 100644 index 0000000..b000674 --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/SqlDateColumnConverter.java @@ -0,0 +1,28 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class SqlDateColumnConverter implements ColumnConverter { + @Override + public java.sql.Date getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : new java.sql.Date(cursor.getLong(index)); + } + + @Override + public Object fieldValue2DbValue(java.sql.Date fieldValue) { + if (fieldValue == null) return null; + return fieldValue.getTime(); + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.INTEGER; + } +} diff --git a/app/src/main/java/org/xutils/db/converter/StringColumnConverter.java b/app/src/main/java/org/xutils/db/converter/StringColumnConverter.java new file mode 100644 index 0000000..d3850c6 --- /dev/null +++ b/app/src/main/java/org/xutils/db/converter/StringColumnConverter.java @@ -0,0 +1,27 @@ +package org.xutils.db.converter; + +import android.database.Cursor; + +import org.xutils.db.sqlite.ColumnDbType; + +/** + * Author: wyouflf + * Date: 13-11-4 + * Time: 下午10:51 + */ +public class StringColumnConverter implements ColumnConverter { + @Override + public String getFieldValue(final Cursor cursor, int index) { + return cursor.isNull(index) ? null : cursor.getString(index); + } + + @Override + public Object fieldValue2DbValue(String fieldValue) { + return fieldValue; + } + + @Override + public ColumnDbType getColumnDbType() { + return ColumnDbType.TEXT; + } +} diff --git a/app/src/main/java/org/xutils/db/sqlite/ColumnDbType.java b/app/src/main/java/org/xutils/db/sqlite/ColumnDbType.java new file mode 100644 index 0000000..4bb8998 --- /dev/null +++ b/app/src/main/java/org/xutils/db/sqlite/ColumnDbType.java @@ -0,0 +1,20 @@ +package org.xutils.db.sqlite; + +/** + * Created by wyouflf on 14-2-20. + */ +public enum ColumnDbType { + + INTEGER("INTEGER"), REAL("REAL"), TEXT("TEXT"), BLOB("BLOB"); + + private String value; + + ColumnDbType(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/app/src/main/java/org/xutils/db/sqlite/SqlInfo.java b/app/src/main/java/org/xutils/db/sqlite/SqlInfo.java new file mode 100644 index 0000000..ce18aa6 --- /dev/null +++ b/app/src/main/java/org/xutils/db/sqlite/SqlInfo.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.sqlite; + +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; + +import org.xutils.common.util.KeyValue; +import org.xutils.db.converter.ColumnConverter; +import org.xutils.db.converter.ColumnConverterFactory; +import org.xutils.db.table.ColumnUtils; + +import java.util.ArrayList; +import java.util.List; + +public final class SqlInfo { + + private String sql; + private List bindArgs; + + public SqlInfo() { + } + + public SqlInfo(String sql) { + this.sql = sql; + } + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public void addBindArg(KeyValue kv) { + if (bindArgs == null) { + bindArgs = new ArrayList(); + } + bindArgs.add(kv); + } + + public void addBindArgs(List bindArgs) { + if (this.bindArgs == null) { + this.bindArgs = bindArgs; + } else { + this.bindArgs.addAll(bindArgs); + } + } + + @SuppressWarnings("unchecked") + public SQLiteStatement buildStatement(SQLiteDatabase database) { + SQLiteStatement result = database.compileStatement(sql); + if (bindArgs != null) { + for (int i = 1; i < bindArgs.size() + 1; i++) { + KeyValue kv = bindArgs.get(i - 1); + if (kv.value == null) { + result.bindNull(i); + continue; + } + ColumnConverter converter = ColumnConverterFactory.getColumnConverter(kv.value.getClass()); + Object value = converter.fieldValue2DbValue(kv.value); + ColumnDbType type = converter.getColumnDbType(); + switch (type) { + case INTEGER: + result.bindLong(i, ((Number) value).longValue()); + break; + case REAL: + result.bindDouble(i, ((Number) value).doubleValue()); + break; + case TEXT: + result.bindString(i, value.toString()); + break; + case BLOB: + result.bindBlob(i, (byte[]) value); + break; + default: + result.bindNull(i); + break; + } // end switch + } + } + return result; + } + + public Object[] getBindArgs() { + Object[] result = null; + if (bindArgs != null) { + result = new Object[bindArgs.size()]; + for (int i = 0; i < bindArgs.size(); i++) { + result[i] = ColumnUtils.convert2DbValueIfNeeded(bindArgs.get(i).value); + } + } + return result; + } + + public String[] getBindArgsAsStrArray() { + String[] result = null; + if (bindArgs != null) { + result = new String[bindArgs.size()]; + for (int i = 0; i < bindArgs.size(); i++) { + Object value = ColumnUtils.convert2DbValueIfNeeded(bindArgs.get(i).value); + result[i] = value == null ? null : value.toString(); + } + } + return result; + } +} diff --git a/app/src/main/java/org/xutils/db/sqlite/SqlInfoBuilder.java b/app/src/main/java/org/xutils/db/sqlite/SqlInfoBuilder.java new file mode 100644 index 0000000..f16436d --- /dev/null +++ b/app/src/main/java/org/xutils/db/sqlite/SqlInfoBuilder.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.sqlite; + +import org.xutils.common.util.KeyValue; +import org.xutils.db.table.ColumnEntity; +import org.xutils.db.table.TableEntity; +import org.xutils.ex.DbException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Build "insert", "replace",,"update", "delete" and "create" sql. + */ +public final class SqlInfoBuilder { + + private static final ConcurrentHashMap, String> INSERT_SQL_CACHE = new ConcurrentHashMap, String>(); + private static final ConcurrentHashMap, String> REPLACE_SQL_CACHE = new ConcurrentHashMap, String>(); + + private SqlInfoBuilder() { + } + + //*********************************************** insert sql *********************************************** + + public static SqlInfo buildInsertSqlInfo(TableEntity table, Object entity) throws DbException { + + List keyValueList = entity2KeyValueList(table, entity); + if (keyValueList.size() == 0) return null; + + SqlInfo result = new SqlInfo(); + String sql = INSERT_SQL_CACHE.get(table); + if (sql == null) { + StringBuilder builder = new StringBuilder(); + builder.append("INSERT INTO "); + builder.append("\"").append(table.getName()).append("\""); + builder.append(" ("); + for (KeyValue kv : keyValueList) { + builder.append("\"").append(kv.key).append("\"").append(','); + } + builder.deleteCharAt(builder.length() - 1); + builder.append(") VALUES ("); + + int length = keyValueList.size(); + for (int i = 0; i < length; i++) { + builder.append("?,"); + } + builder.deleteCharAt(builder.length() - 1); + builder.append(")"); + + sql = builder.toString(); + result.setSql(sql); + result.addBindArgs(keyValueList); + INSERT_SQL_CACHE.put(table, sql); + } else { + result.setSql(sql); + result.addBindArgs(keyValueList); + } + + return result; + } + + //*********************************************** replace sql *********************************************** + + public static SqlInfo buildReplaceSqlInfo(TableEntity table, Object entity) throws DbException { + + List keyValueList = entity2KeyValueList(table, entity); + if (keyValueList.size() == 0) return null; + + SqlInfo result = new SqlInfo(); + String sql = REPLACE_SQL_CACHE.get(table); + if (sql == null) { + StringBuilder builder = new StringBuilder(); + builder.append("REPLACE INTO "); + builder.append("\"").append(table.getName()).append("\""); + builder.append(" ("); + for (KeyValue kv : keyValueList) { + builder.append("\"").append(kv.key).append("\"").append(','); + } + builder.deleteCharAt(builder.length() - 1); + builder.append(") VALUES ("); + + int length = keyValueList.size(); + for (int i = 0; i < length; i++) { + builder.append("?,"); + } + builder.deleteCharAt(builder.length() - 1); + builder.append(")"); + + sql = builder.toString(); + result.setSql(sql); + result.addBindArgs(keyValueList); + REPLACE_SQL_CACHE.put(table, sql); + } else { + result.setSql(sql); + result.addBindArgs(keyValueList); + } + + return result; + } + + //*********************************************** delete sql *********************************************** + + public static SqlInfo buildDeleteSqlInfo(TableEntity table, Object entity) throws DbException { + SqlInfo result = new SqlInfo(); + + ColumnEntity id = table.getId(); + Object idValue = id.getColumnValue(entity); + + if (idValue == null) { + throw new DbException("this entity[" + table.getEntityType() + "]'s id value is null"); + } + StringBuilder builder = new StringBuilder("DELETE FROM "); + builder.append("\"").append(table.getName()).append("\""); + builder.append(" WHERE ").append(WhereBuilder.b(id.getName(), "=", idValue)); + + result.setSql(builder.toString()); + + return result; + } + + public static SqlInfo buildDeleteSqlInfoById(TableEntity table, Object idValue) throws DbException { + SqlInfo result = new SqlInfo(); + + ColumnEntity id = table.getId(); + + if (idValue == null) { + throw new DbException("this entity[" + table.getEntityType() + "]'s id value is null"); + } + StringBuilder builder = new StringBuilder("DELETE FROM "); + builder.append("\"").append(table.getName()).append("\""); + builder.append(" WHERE ").append(WhereBuilder.b(id.getName(), "=", idValue)); + + result.setSql(builder.toString()); + + return result; + } + + public static SqlInfo buildDeleteSqlInfo(TableEntity table, WhereBuilder whereBuilder) throws DbException { + StringBuilder builder = new StringBuilder("DELETE FROM "); + builder.append("\"").append(table.getName()).append("\""); + + if (whereBuilder != null && whereBuilder.getWhereItemSize() > 0) { + builder.append(" WHERE ").append(whereBuilder.toString()); + } + + return new SqlInfo(builder.toString()); + } + + //*********************************************** update sql *********************************************** + + public static SqlInfo buildUpdateSqlInfo(TableEntity table, Object entity, String... updateColumnNames) throws DbException { + + List keyValueList = entity2KeyValueList(table, entity); + if (keyValueList.size() == 0) return null; + + HashSet updateColumnNameSet = null; + if (updateColumnNames != null && updateColumnNames.length > 0) { + updateColumnNameSet = new HashSet(updateColumnNames.length); + Collections.addAll(updateColumnNameSet, updateColumnNames); + } + + ColumnEntity id = table.getId(); + Object idValue = id.getColumnValue(entity); + + if (idValue == null) { + throw new DbException("this entity[" + table.getEntityType() + "]'s id value is null"); + } + + SqlInfo result = new SqlInfo(); + StringBuilder builder = new StringBuilder("UPDATE "); + builder.append("\"").append(table.getName()).append("\""); + builder.append(" SET "); + for (KeyValue kv : keyValueList) { + if (updateColumnNameSet == null || updateColumnNameSet.contains(kv.key)) { + builder.append("\"").append(kv.key).append("\"").append("=?,"); + result.addBindArg(kv); + } + } + builder.deleteCharAt(builder.length() - 1); + builder.append(" WHERE ").append(WhereBuilder.b(id.getName(), "=", idValue)); + + result.setSql(builder.toString()); + return result; + } + + public static SqlInfo buildUpdateSqlInfo(TableEntity table, WhereBuilder whereBuilder, KeyValue... nameValuePairs) throws DbException { + + if (nameValuePairs == null || nameValuePairs.length == 0) return null; + + SqlInfo result = new SqlInfo(); + StringBuilder builder = new StringBuilder("UPDATE "); + builder.append("\"").append(table.getName()).append("\""); + builder.append(" SET "); + for (KeyValue kv : nameValuePairs) { + builder.append("\"").append(kv.key).append("\"").append("=?,"); + result.addBindArg(kv); + } + builder.deleteCharAt(builder.length() - 1); + if (whereBuilder != null && whereBuilder.getWhereItemSize() > 0) { + builder.append(" WHERE ").append(whereBuilder.toString()); + } + + result.setSql(builder.toString()); + return result; + } + + //*********************************************** others *********************************************** + + public static SqlInfo buildCreateTableSqlInfo(TableEntity table) throws DbException { + ColumnEntity id = table.getId(); + + StringBuilder builder = new StringBuilder(); + builder.append("CREATE TABLE IF NOT EXISTS "); + builder.append("\"").append(table.getName()).append("\""); + builder.append(" ( "); + + if (id.isAutoId()) { + builder.append("\"").append(id.getName()).append("\"").append(" INTEGER PRIMARY KEY AUTOINCREMENT, "); + } else { + builder.append("\"").append(id.getName()).append("\"").append(id.getColumnDbType()).append(" PRIMARY KEY, "); + } + + Collection columns = table.getColumnMap().values(); + for (ColumnEntity column : columns) { + if (column.isId()) continue; + builder.append("\"").append(column.getName()).append("\""); + builder.append(' ').append(column.getColumnDbType()); + builder.append(' ').append(column.getProperty()); + builder.append(','); + } + + builder.deleteCharAt(builder.length() - 1); + builder.append(" )"); + return new SqlInfo(builder.toString()); + } + + public static List entity2KeyValueList(TableEntity table, Object entity) { + + Collection columns = table.getColumnMap().values(); + List keyValueList = new ArrayList(columns.size()); + for (ColumnEntity column : columns) { + KeyValue kv = column2KeyValue(entity, column); + if (kv != null) { + keyValueList.add(kv); + } + } + + return keyValueList; + } + + private static KeyValue column2KeyValue(Object entity, ColumnEntity column) { + if (column.isAutoId()) { + return null; + } + + String key = column.getName(); + Object value = column.getFieldValue(entity); + return new KeyValue(key, value); + } +} diff --git a/app/src/main/java/org/xutils/db/sqlite/WhereBuilder.java b/app/src/main/java/org/xutils/db/sqlite/WhereBuilder.java new file mode 100644 index 0000000..52957f4 --- /dev/null +++ b/app/src/main/java/org/xutils/db/sqlite/WhereBuilder.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.sqlite; + +import android.text.TextUtils; + +import org.xutils.db.table.ColumnUtils; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Author: wyouflf + * Date: 13-7-29 + * Time: 上午9:35 + */ +public class WhereBuilder { + + private final List whereItems; + + private WhereBuilder() { + this.whereItems = new ArrayList(); + } + + /** + * create new instance + */ + public static WhereBuilder b() { + return new WhereBuilder(); + } + + /** + * create new instance + * + * @param op operator: "=","LIKE","IN","BETWEEN"... + */ + public static WhereBuilder b(String columnName, String op, Object value) { + WhereBuilder result = new WhereBuilder(); + result.appendCondition(null, columnName, op, value); + return result; + } + + /** + * add AND condition + * + * @param op operator: "=","LIKE","IN","BETWEEN"... + */ + public WhereBuilder and(String columnName, String op, Object value) { + appendCondition(whereItems.size() == 0 ? null : "AND", columnName, op, value); + return this; + } + + /** + * add AND condition + * + * @param where expr("[AND] (" + where.toString() + ")") + */ + public WhereBuilder and(WhereBuilder where) { + String condition = whereItems.size() == 0 ? " " : "AND "; + return expr(condition + "(" + where.toString() + ")"); + } + + /** + * add OR condition + * + * @param op operator: "=","LIKE","IN","BETWEEN"... + */ + public WhereBuilder or(String columnName, String op, Object value) { + appendCondition(whereItems.size() == 0 ? null : "OR", columnName, op, value); + return this; + } + + /** + * add OR condition + * + * @param where expr("[OR] (" + where.toString() + ")") + */ + public WhereBuilder or(WhereBuilder where) { + String condition = whereItems.size() == 0 ? " " : "OR "; + return expr(condition + "(" + where.toString() + ")"); + } + + public WhereBuilder expr(String expr) { + whereItems.add(" " + expr); + return this; + } + + public int getWhereItemSize() { + return whereItems.size(); + } + + @Override + public String toString() { + if (whereItems.size() == 0) { + return ""; + } + StringBuilder sb = new StringBuilder(); + for (String item : whereItems) { + sb.append(item); + } + return sb.toString(); + } + + private void appendCondition(String conj, String columnName, String op, Object value) { + StringBuilder builder = new StringBuilder(); + + if (whereItems.size() > 0) { + builder.append(" "); + } + + // append conj + if (!TextUtils.isEmpty(conj)) { + builder.append(conj).append(" "); + } + + // append columnName + builder.append("\"").append(columnName).append("\""); + + // convert op + if ("!=".equals(op)) { + op = "<>"; + } else if ("==".equals(op)) { + op = "="; + } + + // append op & value + if (value == null) { + if ("=".equals(op)) { + builder.append(" IS NULL"); + } else if ("<>".equals(op)) { + builder.append(" IS NOT NULL"); + } else { + builder.append(" ").append(op).append(" NULL"); + } + } else { + builder.append(" ").append(op).append(" "); + + if ("IN".equalsIgnoreCase(op)) { + Iterable items = null; + if (value instanceof Iterable) { + items = (Iterable) value; + } else if (value.getClass().isArray()) { + int len = Array.getLength(value); + List arrayList = new ArrayList(len); + for (int i = 0; i < len; i++) { + arrayList.add(Array.get(value, i)); + } + items = arrayList; + } + if (items != null) { + StringBuilder inSb = new StringBuilder("("); + for (Object item : items) { + Object itemColValue = ColumnUtils.convert2DbValueIfNeeded(item); + if (ColumnUtils.isTextColumnDbType(itemColValue)) { + String valueStr = ColumnUtils.convert2SafeExpr(itemColValue); + inSb.append("'").append(valueStr).append("'"); + } else { + inSb.append(itemColValue); + } + inSb.append(","); + } + if (inSb.length() > 1) { + inSb.deleteCharAt(inSb.length() - 1); + } + inSb.append(")"); + builder.append(inSb.toString()); + } else { + throw new IllegalArgumentException("value must be an Array or an Iterable."); + } + } else if ("BETWEEN".equalsIgnoreCase(op)) { + Iterable items = null; + if (value instanceof Iterable) { + items = (Iterable) value; + } else if (value.getClass().isArray()) { + int len = Array.getLength(value); + List arrayList = new ArrayList(len); + for (int i = 0; i < len; i++) { + arrayList.add(Array.get(value, i)); + } + items = arrayList; + } + if (items != null) { + Iterator iterator = items.iterator(); + if (!iterator.hasNext()) + throw new IllegalArgumentException("value must contains tow items."); + Object start = iterator.next(); + if (!iterator.hasNext()) + throw new IllegalArgumentException("value must contains tow items."); + Object end = iterator.next(); + + Object startColValue = ColumnUtils.convert2DbValueIfNeeded(start); + Object endColValue = ColumnUtils.convert2DbValueIfNeeded(end); + + if (ColumnUtils.isTextColumnDbType(startColValue)) { + String startStr = ColumnUtils.convert2SafeExpr(startColValue); + String endStr = ColumnUtils.convert2SafeExpr(endColValue); + builder.append("'").append(startStr).append("'"); + builder.append(" AND "); + builder.append("'").append(endStr).append("'"); + } else { + builder.append(startColValue); + builder.append(" AND "); + builder.append(endColValue); + } + } else { + throw new IllegalArgumentException("value must be an Array or an Iterable."); + } + } else { + value = ColumnUtils.convert2DbValueIfNeeded(value); + if (ColumnUtils.isTextColumnDbType(value)) { + String valueStr = ColumnUtils.convert2SafeExpr(value); + builder.append("'").append(valueStr).append("'"); + } else { + builder.append(value); + } + } + } + whereItems.add(builder.toString()); + } +} diff --git a/app/src/main/java/org/xutils/db/table/ColumnEntity.java b/app/src/main/java/org/xutils/db/table/ColumnEntity.java new file mode 100644 index 0000000..12ea257 --- /dev/null +++ b/app/src/main/java/org/xutils/db/table/ColumnEntity.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.table; + +import android.database.Cursor; + +import org.xutils.common.util.LogUtil; +import org.xutils.db.annotation.Column; +import org.xutils.db.converter.ColumnConverter; +import org.xutils.db.converter.ColumnConverterFactory; +import org.xutils.db.sqlite.ColumnDbType; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public final class ColumnEntity { + + protected final String name; + private final String property; + private final boolean isId; + private final boolean isAutoId; + + protected final Method getMethod; + protected final Method setMethod; + + protected final Field columnField; + protected final ColumnConverter columnConverter; + + /* package */ ColumnEntity(Class entityType, Field field, Column column) { + field.setAccessible(true); + + this.columnField = field; + this.name = column.name(); + this.property = column.property(); + this.isId = column.isId(); + + Class fieldType = field.getType(); + this.isAutoId = this.isId && column.autoGen() && ColumnUtils.isAutoIdType(fieldType); + this.columnConverter = ColumnConverterFactory.getColumnConverter(fieldType); + + + this.getMethod = ColumnUtils.findGetMethod(entityType, field); + if (this.getMethod != null && !this.getMethod.isAccessible()) { + this.getMethod.setAccessible(true); + } + this.setMethod = ColumnUtils.findSetMethod(entityType, field); + if (this.setMethod != null && !this.setMethod.isAccessible()) { + this.setMethod.setAccessible(true); + } + } + + public void setValueFromCursor(Object entity, Cursor cursor, int index) { + Object value = columnConverter.getFieldValue(cursor, index); + if (value == null) return; + + if (setMethod != null) { + try { + setMethod.invoke(entity, value); + } catch (Throwable e) { + LogUtil.e(e.getMessage(), e); + } + } else { + try { + this.columnField.set(entity, value); + } catch (Throwable e) { + LogUtil.e(e.getMessage(), e); + } + } + } + + @SuppressWarnings("unchecked") + public Object getColumnValue(Object entity) { + Object fieldValue = getFieldValue(entity); + if (this.isAutoId && (fieldValue.equals(0L) || fieldValue.equals(0))) { + return null; + } + return columnConverter.fieldValue2DbValue(fieldValue); + } + + public void setAutoIdValue(Object entity, long value) { + Object idValue = value; + if (ColumnUtils.isInteger(columnField.getType())) { + idValue = (int) value; + } + + if (setMethod != null) { + try { + setMethod.invoke(entity, idValue); + } catch (Throwable e) { + LogUtil.e(e.getMessage(), e); + } + } else { + try { + this.columnField.set(entity, idValue); + } catch (Throwable e) { + LogUtil.e(e.getMessage(), e); + } + } + } + + public Object getFieldValue(Object entity) { + Object fieldValue = null; + if (entity != null) { + if (getMethod != null) { + try { + fieldValue = getMethod.invoke(entity); + } catch (Throwable e) { + LogUtil.e(e.getMessage(), e); + } + } else { + try { + fieldValue = this.columnField.get(entity); + } catch (Throwable e) { + LogUtil.e(e.getMessage(), e); + } + } + } + return fieldValue; + } + + public String getName() { + return name; + } + + public String getProperty() { + return property; + } + + public boolean isId() { + return isId; + } + + public boolean isAutoId() { + return isAutoId; + } + + public Field getColumnField() { + return columnField; + } + + public ColumnConverter getColumnConverter() { + return columnConverter; + } + + public ColumnDbType getColumnDbType() { + return columnConverter.getColumnDbType(); + } + + @Override + public String toString() { + return name; + } +} diff --git a/app/src/main/java/org/xutils/db/table/ColumnUtils.java b/app/src/main/java/org/xutils/db/table/ColumnUtils.java new file mode 100644 index 0000000..c82a6a2 --- /dev/null +++ b/app/src/main/java/org/xutils/db/table/ColumnUtils.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.table; + +import org.xutils.common.util.LogUtil; +import org.xutils.db.converter.ColumnConverter; +import org.xutils.db.converter.ColumnConverterFactory; +import org.xutils.db.sqlite.ColumnDbType; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashSet; + +public final class ColumnUtils { + + private ColumnUtils() { + } + + private static final HashSet> BOOLEAN_TYPES = new HashSet>(2); + private static final HashSet> INTEGER_TYPES = new HashSet>(2); + private static final HashSet> AUTO_INCREMENT_TYPES = new HashSet>(4); + + static { + BOOLEAN_TYPES.add(boolean.class); + BOOLEAN_TYPES.add(Boolean.class); + + INTEGER_TYPES.add(int.class); + INTEGER_TYPES.add(Integer.class); + + AUTO_INCREMENT_TYPES.addAll(INTEGER_TYPES); + AUTO_INCREMENT_TYPES.add(long.class); + AUTO_INCREMENT_TYPES.add(Long.class); + } + + public static boolean isAutoIdType(Class fieldType) { + return AUTO_INCREMENT_TYPES.contains(fieldType); + } + + public static boolean isInteger(Class fieldType) { + return INTEGER_TYPES.contains(fieldType); + } + + public static boolean isBoolean(Class fieldType) { + return BOOLEAN_TYPES.contains(fieldType); + } + + public static boolean isTextColumnDbType(Object value) { + if (value == null) return false; + ColumnConverter converter = ColumnConverterFactory.getColumnConverter(value.getClass()); + return converter != null && ColumnDbType.TEXT.equals(converter.getColumnDbType()); + } + + public static String convert2SafeExpr(Object value) { + String result = String.valueOf(value); + if (result.indexOf('\'') != -1) { + result = result.replace("'", "''"); + } + return result; + } + + @SuppressWarnings("unchecked") + public static Object convert2DbValueIfNeeded(final Object value) { + Object result = value; + if (value != null) { + Class valueType = value.getClass(); + ColumnConverter converter = ColumnConverterFactory.getColumnConverter(valueType); + result = converter.fieldValue2DbValue(value); + } + return result; + } + + /* package */ + static Method findGetMethod(Class entityType, Field field) { + if (Object.class.equals(entityType)) return null; + + String fieldName = field.getName(); + Method getMethod = null; + if (isBoolean(field.getType())) { + getMethod = findBooleanGetMethod(entityType, fieldName); + } + if (getMethod == null) { + String methodName = "get" + fieldName.substring(0, 1).toUpperCase(); + if (fieldName.length() > 1) { + methodName += fieldName.substring(1); + } + try { + getMethod = entityType.getDeclaredMethod(methodName); + } catch (NoSuchMethodException e) { + LogUtil.d(entityType.getName() + "#" + methodName + " not exist"); + } + } + + if (getMethod == null) { + return findGetMethod(entityType.getSuperclass(), field); + } + return getMethod; + } + + /* package */ + static Method findSetMethod(Class entityType, Field field) { + if (Object.class.equals(entityType)) return null; + + String fieldName = field.getName(); + Class fieldType = field.getType(); + Method setMethod = null; + if (isBoolean(fieldType)) { + setMethod = findBooleanSetMethod(entityType, fieldName, fieldType); + } + if (setMethod == null) { + String methodName = "set" + fieldName.substring(0, 1).toUpperCase(); + if (fieldName.length() > 1) { + methodName += fieldName.substring(1); + } + try { + setMethod = entityType.getDeclaredMethod(methodName, fieldType); + } catch (NoSuchMethodException e) { + LogUtil.d(entityType.getName() + "#" + methodName + " not exist"); + } + } + + if (setMethod == null) { + return findSetMethod(entityType.getSuperclass(), field); + } + return setMethod; + } + + private static Method findBooleanGetMethod(Class entityType, final String fieldName) { + String methodName = null; + if (fieldName.startsWith("is")) { + methodName = fieldName; + } else { + methodName = "is" + fieldName.substring(0, 1).toUpperCase(); + if (fieldName.length() > 1) { + methodName += fieldName.substring(1); + } + } + try { + return entityType.getDeclaredMethod(methodName); + } catch (NoSuchMethodException e) { + LogUtil.d(entityType.getName() + "#" + methodName + " not exist"); + } + return null; + } + + private static Method findBooleanSetMethod(Class entityType, final String fieldName, Class fieldType) { + String methodName = null; + if (fieldName.startsWith("is") && fieldName.length() > 2) { + methodName = "set" + fieldName.substring(2, 3).toUpperCase(); + if (fieldName.length() > 3) { + methodName += fieldName.substring(3); + } + } else { + methodName = "set" + fieldName.substring(0, 1).toUpperCase(); + if (fieldName.length() > 1) { + methodName += fieldName.substring(1); + } + } + try { + return entityType.getDeclaredMethod(methodName, fieldType); + } catch (NoSuchMethodException e) { + LogUtil.d(entityType.getName() + "#" + methodName + " not exist"); + } + return null; + } + +} diff --git a/app/src/main/java/org/xutils/db/table/DbBase.java b/app/src/main/java/org/xutils/db/table/DbBase.java new file mode 100644 index 0000000..7b8f855 --- /dev/null +++ b/app/src/main/java/org/xutils/db/table/DbBase.java @@ -0,0 +1,99 @@ +package org.xutils.db.table; + +import android.database.Cursor; + +import org.xutils.DbManager; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.ex.DbException; + +import java.util.HashMap; + +/** + * DbManager基类, 包含表结构的基本操作. + * Created by wyouflf on 16/1/22. + */ +public abstract class DbBase implements DbManager { + + private final HashMap, TableEntity> tableMap = new HashMap, TableEntity>(); + + @Override + @SuppressWarnings("unchecked") + public TableEntity getTable(Class entityType) throws DbException { + synchronized (tableMap) { + TableEntity table = (TableEntity) tableMap.get(entityType); + if (table == null) { + try { + table = new TableEntity(this, entityType); + } catch (DbException ex) { + throw ex; + } catch (Throwable ex) { + throw new DbException(ex); + } + tableMap.put(entityType, table); + } + + return table; + } + } + + @Override + public void dropTable(Class entityType) throws DbException { + TableEntity table = this.getTable(entityType); + if (!table.tableIsExists()) return; + execNonQuery("DROP TABLE \"" + table.getName() + "\""); + table.setTableCheckedStatus(false); + this.removeTable(entityType); + } + + @Override + public void dropDb() throws DbException { + Cursor cursor = execQuery("SELECT name FROM sqlite_master WHERE type='table' AND name<>'sqlite_sequence'"); + if (cursor != null) { + try { + while (cursor.moveToNext()) { + try { + String tableName = cursor.getString(0); + execNonQuery("DROP TABLE " + tableName); + } catch (Throwable e) { + LogUtil.e(e.getMessage(), e); + } + } + + synchronized (tableMap) { + for (TableEntity table : tableMap.values()) { + table.setTableCheckedStatus(false); + } + tableMap.clear(); + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + } + + @Override + public void addColumn(Class entityType, String column) throws DbException { + TableEntity table = this.getTable(entityType); + ColumnEntity col = table.getColumnMap().get(column); + if (col != null) { + if (!table.tableIsExists()) return; // 不需要添加, 表创建时会自动添加 + StringBuilder builder = new StringBuilder(); + builder.append("ALTER TABLE ").append("\"").append(table.getName()).append("\""). + append(" ADD COLUMN ").append("\"").append(col.getName()).append("\""). + append(" ").append(col.getColumnDbType()). + append(" ").append(col.getProperty()); + execNonQuery(builder.toString()); + } else { + throw new DbException("the column(" + column + ") is not defined in table: " + table.getName()); + } + } + + protected void removeTable(Class entityType) { + synchronized (tableMap) { + tableMap.remove(entityType); + } + } +} diff --git a/app/src/main/java/org/xutils/db/table/DbModel.java b/app/src/main/java/org/xutils/db/table/DbModel.java new file mode 100644 index 0000000..714f42b --- /dev/null +++ b/app/src/main/java/org/xutils/db/table/DbModel.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.table; + +import android.text.TextUtils; + +import java.util.Date; +import java.util.HashMap; + +public final class DbModel { + + /** + * key: columnName + * value: valueStr + */ + private final HashMap dataMap = new HashMap(); + + public String getString(String columnName) { + return dataMap.get(columnName); + } + + public int getInt(String columnName, int defaultValue) { + String value = dataMap.get(columnName); + if (TextUtils.isEmpty(value)) { + return defaultValue; + } else { + try { + return Integer.valueOf(value); + } catch (Throwable ex) { + return defaultValue; + } + } + } + + public boolean getBoolean(String columnName) { + String value = dataMap.get(columnName); + if (value != null) { + return value.length() == 1 ? "1".equals(value) : Boolean.valueOf(value); + } + return false; + } + + public double getDouble(String columnName, double defaultValue) { + String value = dataMap.get(columnName); + if (TextUtils.isEmpty(value)) { + return defaultValue; + } else { + try { + return Double.valueOf(value); + } catch (Throwable ex) { + return defaultValue; + } + } + } + + public float getFloat(String columnName, float defaultValue) { + String value = dataMap.get(columnName); + if (TextUtils.isEmpty(value)) { + return defaultValue; + } else { + try { + return Float.valueOf(value); + } catch (Throwable ex) { + return defaultValue; + } + } + } + + public long getLong(String columnName, long defaultValue) { + String value = dataMap.get(columnName); + if (TextUtils.isEmpty(value)) { + return defaultValue; + } else { + try { + return Long.valueOf(value); + } catch (Throwable ex) { + return defaultValue; + } + } + } + + public Date getDate(String columnName, long defaultTime) { + return new Date(getLong(columnName, defaultTime)); + } + + public java.sql.Date getSqlDate(String columnName, long defaultTime) { + return new java.sql.Date(getLong(columnName, defaultTime)); + } + + public void add(String columnName, String valueStr) { + dataMap.put(columnName, valueStr); + } + + /** + * @return key: columnName + */ + public HashMap getDataMap() { + return dataMap; + } + + /** + * 列数据是否空 + */ + public boolean isEmpty(String columnName) { + return TextUtils.isEmpty(dataMap.get(columnName)); + } +} diff --git a/app/src/main/java/org/xutils/db/table/TableEntity.java b/app/src/main/java/org/xutils/db/table/TableEntity.java new file mode 100644 index 0000000..5814650 --- /dev/null +++ b/app/src/main/java/org/xutils/db/table/TableEntity.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.table; + +import android.database.Cursor; +import android.text.TextUtils; + +import org.xutils.DbManager; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.db.annotation.Table; +import org.xutils.db.sqlite.SqlInfo; +import org.xutils.db.sqlite.SqlInfoBuilder; +import org.xutils.ex.DbException; + +import java.lang.reflect.Constructor; +import java.util.LinkedHashMap; + + +public final class TableEntity { + + private final DbManager db; + private final String name; + private final String onCreated; + private final Class entityType; + private final Constructor constructor; + private ColumnEntity id; + private volatile Boolean tableCheckedStatus; + + /** + * key: columnName + */ + private final LinkedHashMap columnMap; + + /*package*/ TableEntity(DbManager db, Class entityType) throws Throwable { + this.db = db; + this.entityType = entityType; + + Table table = entityType.getAnnotation(Table.class); + if (table == null) { + throw new DbException("missing @Table on " + entityType.getName()); + } + this.name = table.name(); + this.onCreated = table.onCreated(); + + try { + this.constructor = entityType.getConstructor(); + this.constructor.setAccessible(true); + } catch (Throwable ex) { + throw new DbException("missing no-argument constructor for the table: " + this.name); + } + + this.columnMap = TableUtils.findColumnMap(entityType); + for (ColumnEntity column : columnMap.values()) { + if (column.isId()) { + this.id = column; + break; + } + } + } + + public T createEntity() throws Throwable { + return this.constructor.newInstance(); + } + + public boolean tableIsExists() throws DbException { + return tableIsExists(false); + } + + public boolean tableIsExists(boolean forceCheckFromDb) throws DbException { + if (tableCheckedStatus != null && (tableCheckedStatus || !forceCheckFromDb)) { + return tableCheckedStatus; + } + + Cursor cursor = db.execQuery("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='" + name + "'"); + if (cursor != null) { + try { + if (cursor.moveToNext()) { + int count = cursor.getInt(0); + if (count > 0) { + tableCheckedStatus = true; + return tableCheckedStatus; + } + } + } catch (Throwable e) { + throw new DbException(e); + } finally { + IOUtil.closeQuietly(cursor); + } + } + + tableCheckedStatus = false; + return tableCheckedStatus; + } + + public void createTableIfNotExists() throws DbException { + if (tableCheckedStatus != null && tableCheckedStatus) return; + synchronized (entityType) { + if (!this.tableIsExists(true)) { + SqlInfo sqlInfo = SqlInfoBuilder.buildCreateTableSqlInfo(this); + db.execNonQuery(sqlInfo); + tableCheckedStatus = true; + + if (!TextUtils.isEmpty(onCreated)) { + db.execNonQuery(onCreated); + } + + DbManager.TableCreateListener listener = db.getDaoConfig().getTableCreateListener(); + if (listener != null) { + try { + listener.onTableCreated(db, this); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + } + + public DbManager getDb() { + return db; + } + + public String getName() { + return name; + } + + public Class getEntityType() { + return entityType; + } + + public String getOnCreated() { + return onCreated; + } + + public ColumnEntity getId() { + return id; + } + + public LinkedHashMap getColumnMap() { + return columnMap; + } + + /*package*/ void setTableCheckedStatus(boolean tableCheckedStatus) { + this.tableCheckedStatus = tableCheckedStatus; + } + + @Override + public String toString() { + return name; + } +} diff --git a/app/src/main/java/org/xutils/db/table/TableUtils.java b/app/src/main/java/org/xutils/db/table/TableUtils.java new file mode 100644 index 0000000..3fae37b --- /dev/null +++ b/app/src/main/java/org/xutils/db/table/TableUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.db.table; + +import org.xutils.common.util.LogUtil; +import org.xutils.db.annotation.Column; +import org.xutils.db.converter.ColumnConverterFactory; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.LinkedHashMap; + +/* package */ final class TableUtils { + + private TableUtils() { + } + + /* package */ + static LinkedHashMap findColumnMap(Class entityType) { + LinkedHashMap columnMap = new LinkedHashMap(); + addColumns2Map(entityType, columnMap); + return columnMap; + } + + private static void addColumns2Map(Class entityType, HashMap columnMap) { + if (Object.class.equals(entityType)) return; + + try { + Field[] fields = entityType.getDeclaredFields(); + for (Field field : fields) { + int modify = field.getModifiers(); + if (Modifier.isStatic(modify) || Modifier.isTransient(modify)) { + continue; + } + Column columnAnn = field.getAnnotation(Column.class); + if (columnAnn != null) { + if (ColumnConverterFactory.isSupportColumnConverter(field.getType())) { + ColumnEntity column = new ColumnEntity(entityType, field, columnAnn); + if (!columnMap.containsKey(column.getName())) { + columnMap.put(column.getName(), column); + } + } + } + } + + addColumns2Map(entityType.getSuperclass(), columnMap); + } catch (Throwable e) { + LogUtil.e(e.getMessage(), e); + } + } +} diff --git a/app/src/main/java/org/xutils/ex/BaseException.java b/app/src/main/java/org/xutils/ex/BaseException.java new file mode 100644 index 0000000..062ae71 --- /dev/null +++ b/app/src/main/java/org/xutils/ex/BaseException.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.ex; + +import java.io.IOException; + +/** + * Author: wyouflf + * Date: 13-7-24 + * Time: 下午3:00 + */ +public class BaseException extends IOException { + private static final long serialVersionUID = 1L; + + public BaseException() { + super(); + } + + public BaseException(String detailMessage) { + super(detailMessage); + } + + public BaseException(String detailMessage, Throwable throwable) { + super(detailMessage); + this.initCause(throwable); + } + + public BaseException(Throwable throwable) { + super(throwable.getMessage()); + this.initCause(throwable); + } +} diff --git a/app/src/main/java/org/xutils/ex/DbException.java b/app/src/main/java/org/xutils/ex/DbException.java new file mode 100644 index 0000000..7a49641 --- /dev/null +++ b/app/src/main/java/org/xutils/ex/DbException.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.ex; + +public class DbException extends BaseException { + private static final long serialVersionUID = 1L; + + public DbException() { + } + + public DbException(String detailMessage) { + super(detailMessage); + } + + public DbException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } + + public DbException(Throwable throwable) { + super(throwable); + } +} diff --git a/app/src/main/java/org/xutils/ex/FileLockedException.java b/app/src/main/java/org/xutils/ex/FileLockedException.java new file mode 100644 index 0000000..3e353ec --- /dev/null +++ b/app/src/main/java/org/xutils/ex/FileLockedException.java @@ -0,0 +1,12 @@ +package org.xutils.ex; + +/** + * Created by wyouflf on 15/10/9. + */ +public class FileLockedException extends BaseException { + private static final long serialVersionUID = 1L; + + public FileLockedException(String detailMessage) { + super(detailMessage); + } +} diff --git a/app/src/main/java/org/xutils/ex/HttpException.java b/app/src/main/java/org/xutils/ex/HttpException.java new file mode 100644 index 0000000..8fb7759 --- /dev/null +++ b/app/src/main/java/org/xutils/ex/HttpException.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.ex; + +import android.text.TextUtils; + +public class HttpException extends BaseException { + private static final long serialVersionUID = 1L; + + private int code; + private String errorCode; + private String customMessage; + private String result; + + /** + * @param code The http response status code, 0 if the http request error and has no response. + * @param detailMessage The http response message. + */ + public HttpException(int code, String detailMessage) { + super(detailMessage); + this.code = code; + } + + public void setCode(int code) { + this.code = code; + } + + public void setMessage(String message) { + this.customMessage = message; + } + + /** + * @return The http response status code, 0 if the http request error and has no response. + */ + public int getCode() { + return code; + } + + public String getErrorCode() { + return errorCode == null ? String.valueOf(code) : errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + @Override + public String getMessage() { + if (!TextUtils.isEmpty(customMessage)) { + return customMessage; + } else { + return super.getMessage(); + } + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + @Override + public String toString() { + return "errorCode: " + getErrorCode() + ", msg: " + getMessage() + ", result: " + result; + } +} diff --git a/app/src/main/java/org/xutils/ex/HttpRedirectException.java b/app/src/main/java/org/xutils/ex/HttpRedirectException.java new file mode 100644 index 0000000..de7c3d1 --- /dev/null +++ b/app/src/main/java/org/xutils/ex/HttpRedirectException.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.ex; + +public class HttpRedirectException extends HttpException { + private static final long serialVersionUID = 1L; + + public HttpRedirectException(int code, String detailMessage, String result) { + super(code, detailMessage); + this.setResult(result); + } +} diff --git a/app/src/main/java/org/xutils/http/BaseParams.java b/app/src/main/java/org/xutils/http/BaseParams.java new file mode 100644 index 0000000..4d64b1b --- /dev/null +++ b/app/src/main/java/org/xutils/http/BaseParams.java @@ -0,0 +1,524 @@ +package org.xutils.http; + +import android.text.TextUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.xutils.common.util.KeyValue; +import org.xutils.common.util.LogUtil; +import org.xutils.http.body.FileBody; +import org.xutils.http.body.InputStreamBody; +import org.xutils.http.body.MultipartBody; +import org.xutils.http.body.RequestBody; +import org.xutils.http.body.StringBody; +import org.xutils.http.body.UrlEncodedBody; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * 请求的基础参数 + * Created by wyouflf on 16/1/23. + */ +public abstract class BaseParams { + + private String charset = "UTF-8"; + private HttpMethod method; + private String bodyContent; + private String bodyContentType; + private boolean multipart = false; // 是否使用multipart表单 + private boolean asJsonContent = false; // 用json形式的bodyParams上传 + private boolean asJsonArrayContent = false; // 用json array形式的bodyParams上传 + private RequestBody requestBody; // 生成的表单 + + private final List
headers = new ArrayList
(); + private final List queryStringParams = new ArrayList(); + private final List bodyParams = new ArrayList(); + + public void setCharset(String charset) { + if (!TextUtils.isEmpty(charset)) { + this.charset = charset; + } + } + + public String getCharset() { + return charset; + } + + public void setMethod(HttpMethod method) { + this.method = method; + } + + public HttpMethod getMethod() { + return method; + } + + public boolean isMultipart() { + return multipart; + } + + public void setMultipart(boolean multipart) { + this.multipart = multipart; + } + + /** + * 以json形式提交body参数 + */ + public boolean isAsJsonContent() { + return asJsonContent; + } + + /** + * 以json形式提交body参数 + */ + public void setAsJsonContent(boolean asJsonContent) { + this.asJsonContent = asJsonContent; + } + + + /** + * 以 json array 形式提交body参数 + */ + public boolean isAsJsonArrayContent() { + return asJsonArrayContent; + } + + /** + * 以 json array 形式提交body参数 + */ + public void setAsJsonArrayContent(boolean asJsonArrayContent) { + this.asJsonArrayContent = asJsonArrayContent; + } + + /** + * 覆盖header + * + * @param name 为空时不添加该参数 + */ + public void setHeader(String name, String value) { + if (TextUtils.isEmpty(name)) return; + Header header = new Header(name, value, true); + Iterator
it = headers.iterator(); + while (it.hasNext()) { + KeyValue kv = it.next(); + if (name.equals(kv.key)) { + it.remove(); + } + } + this.headers.add(header); + } + + /** + * 添加header + * + * @param name 为空时不添加该参数 + */ + public void addHeader(String name, String value) { + if (TextUtils.isEmpty(name)) return; + this.headers.add(new Header(name, value, false)); + } + + /** + * 添加请求参数(根据请求谓词, 将参数加入QueryString或Body.) + * + * @param name 参数名(单个File/InputStream/byte[]数据表单允许name为空) + * @param value 可以是String, File, InputStream 或 byte[] + */ + public void addParameter(String name, Object value) { + if (HttpMethod.permitsRequestBody(method)) { + addBodyParameter(name, value, null, null); + } else { + addQueryStringParameter(name, value); + } + } + + /** + * 添加参数至Query String + * + * @param name 参数名, 为空时不添加该参数 + * @param value 字符串值, 也可以是String集合或数组 + */ + public void addQueryStringParameter(String name, Object value) { + if (TextUtils.isEmpty(name)) return; + if (value instanceof Iterable) { + for (Object item : (Iterable) value) { + this.queryStringParams.add(new ArrayItem(name, item)); + } + } else if (value instanceof JSONArray) { + JSONArray array = (JSONArray) value; + int len = array.length(); + for (int i = 0; i < len; i++) { + this.queryStringParams.add(new ArrayItem(name, array.opt(i))); + } + } else if (value != null && value.getClass().isArray()) { + int len = Array.getLength(value); + for (int i = 0; i < len; i++) { + this.queryStringParams.add(new ArrayItem(name, Array.get(value, i))); + } + } else { + this.queryStringParams.add(new KeyValue(name, value)); + } + } + + /** + * 添加body参数 + * + * @param name 参数名(单个File/InputStream/byte[]数据表单允许name为空) + * @param value 可以是String, File, InputStream 或 byte[] + */ + public void addBodyParameter(String name, Object value) { + addBodyParameter(name, value, null, null); + } + + /** + * 添加body参数 + * + * @param name 参数名(单个File/InputStream/byte[]数据表单允许name为空) + * @param value 可以是String, File, InputStream 或 byte[] + * @param contentType 可为空 + */ + public void addBodyParameter(String name, Object value, String contentType) { + addBodyParameter(name, value, contentType, null); + } + + /** + * 添加body参数 + * + * @param name 参数名(单个File/InputStream/byte[]数据表单允许name为空) + * @param value 可以是String, File, InputStream 或 byte[] + * @param contentType 可为空 + * @param fileName 服务端看到的文件名 + */ + public void addBodyParameter(String name, Object value, String contentType, String fileName) { + if (TextUtils.isEmpty(name) && value == null) return; + if (TextUtils.isEmpty(contentType) && TextUtils.isEmpty(fileName)) { + if (value instanceof Iterable) { + for (Object item : (Iterable) value) { + this.bodyParams.add(new ArrayItem(name, item)); + } + } else if (value instanceof JSONArray) { + JSONArray array = (JSONArray) value; + int len = array.length(); + for (int i = 0; i < len; i++) { + this.bodyParams.add(new ArrayItem(name, array.opt(i))); + } + } else if (value instanceof byte[]) { + this.bodyParams.add(new KeyValue(name, value)); + } else if (value != null && value.getClass().isArray()) { + int len = Array.getLength(value); + for (int i = 0; i < len; i++) { + this.bodyParams.add(new ArrayItem(name, Array.get(value, i))); + } + } else { + this.bodyParams.add(new KeyValue(name, value)); + } + } else { + this.bodyParams.add(new BodyItemWrapper(name, value, contentType, fileName)); + } + } + + public void setBodyContent(String content) { + this.bodyContent = content; + } + + public String getBodyContent() { + checkBodyParams(); + return bodyContent; + } + + /** + * 设置POST等请求的 Content-Type + * + * @param bodyContentType multipart表单仅设置subType(例如:"form-data"(默认) or "related"); + * kv结构自定义设置会被忽略, 默认使用:"application/x-www-form-urlencoded;charset=" + charset; + * 字符串内容表单默认使用: "application/json;charset=" + charset; + * File表单默认尝试使用文件名匹配Content-Type, 匹配失败使用:"application/octet-stream"; + * InputStream表单默认使用: "application/octet-stream"; + */ + public void setBodyContentType(String bodyContentType) { + this.bodyContentType = bodyContentType; + } + + public List
getHeaders() { + return new ArrayList
(headers); + } + + public List getQueryStringParams() { + checkBodyParams(); + return new ArrayList(queryStringParams); + } + + public List getBodyParams() { + checkBodyParams(); + return new ArrayList(bodyParams); + } + + public List getParams(String name) { + List result = new ArrayList(); + for (KeyValue kv : queryStringParams) { + if (name != null && name.equals(kv.key)) { + result.add(kv); + } + } + for (KeyValue kv : bodyParams) { + if (name == null && kv.key == null) { + result.add(kv); + } else if (name != null && name.equals(kv.key)) { + result.add(kv); + } + } + return result; + } + + public void clearParams() { + queryStringParams.clear(); + bodyParams.clear(); + bodyContent = null; + bodyContentType = null; + requestBody = null; + } + + public void removeParameter(String name) { + if (TextUtils.isEmpty(name)) { + bodyContent = null; + bodyContentType = null; + } else { + Iterator it = queryStringParams.iterator(); + while (it.hasNext()) { + KeyValue kv = it.next(); + if (name.equals(kv.key)) { + it.remove(); + } + } + } + + Iterator it = bodyParams.iterator(); + while (it.hasNext()) { + KeyValue kv = it.next(); + if (name == null && kv.key == null) { + it.remove(); + } else if (name != null && name.equals(kv.key)) { + it.remove(); + } + } + } + + public void setRequestBody(RequestBody requestBody) { + this.requestBody = requestBody; + } + + public RequestBody getRequestBody() throws IOException { + checkBodyParams(); + if (this.requestBody != null) { + return this.requestBody; + } + + RequestBody result = null; + if (!TextUtils.isEmpty(bodyContent)) { + result = new StringBody(bodyContent, charset); + result.setContentType(bodyContentType); + } else if (multipart) { + result = new MultipartBody(bodyParams, charset); + result.setContentType(bodyContentType); + } else if (bodyParams.size() == 1) { + KeyValue kv = bodyParams.get(0); + String name = kv.key; + Object value = kv.value; + String contentType = null; + if (kv instanceof BodyItemWrapper) { + BodyItemWrapper wrapper = (BodyItemWrapper) kv; + contentType = wrapper.contentType; + } + if (TextUtils.isEmpty(contentType)) { + contentType = bodyContentType; + } + if (value instanceof File) { + result = new FileBody((File) value, contentType); + } else if (value instanceof InputStream) { + result = new InputStreamBody((InputStream) value, contentType); + } else if (value instanceof byte[]) { + result = new InputStreamBody(new ByteArrayInputStream((byte[]) value), contentType); + } else { + if (TextUtils.isEmpty(name)) { + result = new StringBody(kv.getValueStrOrEmpty(), charset); + result.setContentType(contentType); + } else { + result = new UrlEncodedBody(bodyParams, charset); + result.setContentType(contentType); + } + } + } else { + result = new UrlEncodedBody(bodyParams, charset); + result.setContentType(bodyContentType); + } + + return result; + } + + public String toJSONString() throws JSONException { + return toJSONString(true); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + if (!queryStringParams.isEmpty()) { + for (KeyValue kv : queryStringParams) { + sb.append(kv.key).append("=").append(kv.value).append("&"); + } + sb.deleteCharAt(sb.length() - 1); + } + + if (!TextUtils.isEmpty(bodyContent)) { + sb.append("<").append(bodyContent).append(">"); + } else if (!bodyParams.isEmpty()) { + sb.append("<"); + for (KeyValue kv : bodyParams) { + sb.append(kv.key).append("=").append(kv.value).append("&"); + } + sb.deleteCharAt(sb.length() - 1); + sb.append(">"); + } + return sb.toString(); + } + + private synchronized void checkBodyParams() { + if (bodyParams.isEmpty()) return; + + if (requestBody != null || !HttpMethod.permitsRequestBody(method)) { + queryStringParams.addAll(bodyParams); + bodyParams.clear(); + return; + } + + if (asJsonContent || asJsonArrayContent) { + try { + bodyContent = toJSONString(false); + bodyParams.clear(); + } catch (JSONException ex) { + ex.printStackTrace(); + } + } else if (!TextUtils.isEmpty(bodyContent)) { + queryStringParams.addAll(bodyParams); + bodyParams.clear(); + } + } + + private void params2Json(final JSONObject jsonObject, final List paramList) throws JSONException { + HashSet arraySet = new HashSet(paramList.size()); + LinkedHashMap tempData = new LinkedHashMap(paramList.size()); + for (int i = 0; i < paramList.size(); i++) { + KeyValue kv = paramList.get(i); + final String key = kv.key; + if (TextUtils.isEmpty(key)) continue; + + JSONArray ja = null; + if (tempData.containsKey(key)) { + ja = tempData.get(key); + } else { + ja = new JSONArray(); + tempData.put(key, ja); + } + + ja.put(RequestParamsHelper.parseJSONObject(kv.value)); + + if (kv instanceof ArrayItem) { + arraySet.add(key); + } + } + + for (Map.Entry entry : tempData.entrySet()) { + String key = entry.getKey(); + JSONArray ja = entry.getValue(); + if (ja.length() > 1 || arraySet.contains(key)) { + jsonObject.put(key, ja); + } else { + Object value = ja.get(0); + jsonObject.put(key, value); + } + } + } + + private String toJSONString(boolean withQueryString) throws JSONException { + JSONArray jsonArray = null; + JSONObject jsonObject = null; + if (!TextUtils.isEmpty(bodyContent)) { + if (bodyContent.trim().startsWith("[")) { + jsonArray = new JSONArray(bodyContent); + if (jsonArray.length() > 0) { + Object first = jsonArray.get(0); + if (first instanceof JSONObject) { + jsonObject = (JSONObject) first; + } else { + LogUtil.w("only contains bodyContent"); + return jsonArray.toString(); + } + } else { + jsonObject = new JSONObject(); + jsonArray.put(jsonObject); + } + } else { + jsonObject = new JSONObject(bodyContent); + } + } else { + jsonObject = new JSONObject(); + if (asJsonArrayContent) { + jsonArray = new JSONArray(); + jsonArray.put(jsonObject); + } + } + + if (withQueryString) { + List list = new ArrayList(queryStringParams.size() + bodyParams.size()); + list.addAll(queryStringParams); + list.addAll(bodyParams); + params2Json(jsonObject, list); + } else { + params2Json(jsonObject, bodyParams); + } + + return jsonArray != null ? jsonArray.toString() : jsonObject.toString(); + } + + public static final class ArrayItem extends KeyValue { + public ArrayItem(String key, Object value) { + super(key, value); + } + } + + public static final class Header extends KeyValue { + + public final boolean setHeader; + + public Header(String key, String value, boolean setHeader) { + super(key, value); + this.setHeader = setHeader; + } + } + + public static final class BodyItemWrapper extends KeyValue { + + public final String fileName; + public final String contentType; + + public BodyItemWrapper(String key, Object value, String contentType, String fileName) { + super(key, value); + if (TextUtils.isEmpty(contentType)) { + this.contentType = "application/octet-stream"; + } else { + this.contentType = contentType; + } + this.fileName = fileName; + } + } +} diff --git a/app/src/main/java/org/xutils/http/HttpManagerImpl.java b/app/src/main/java/org/xutils/http/HttpManagerImpl.java new file mode 100644 index 0000000..46cdeb9 --- /dev/null +++ b/app/src/main/java/org/xutils/http/HttpManagerImpl.java @@ -0,0 +1,130 @@ +package org.xutils.http; + +import com.bbit.silk.utils.MyUtil; +import com.bbit.silk.utils.global.Global; +import com.bbit.silk.utils.log.MyLog; + +import org.xutils.HttpManager; +import org.xutils.common.Callback; +import org.xutils.x; + +import java.lang.reflect.Type; +import java.util.List; + +/** + * Created by wyouflf on 15/7/23. + * HttpManager实现 + */ +public final class HttpManagerImpl implements HttpManager { + + private static final Object lock = new Object(); + private static volatile HttpManagerImpl instance; + + private HttpManagerImpl() { + } + + public static void registerInstance() { + if (instance == null) { + synchronized (lock) { + if (instance == null) { + instance = new HttpManagerImpl(); + } + } + } + x.Ext.setHttpManager(instance); + } + + @Override + public Callback.Cancelable get(RequestParams entity, Callback.CommonCallback callback) { + return request(HttpMethod.GET, entity, callback); + } + + @Override + public Callback.Cancelable post(RequestParams entity, Callback.CommonCallback callback) { + return request(HttpMethod.POST, entity, callback); + } + + @Override + public Callback.Cancelable put(RequestParams entity, Callback.CommonCallback callback) { + return request(HttpMethod.PUT, entity, callback); + } + + @Override + public Callback.Cancelable request(HttpMethod method, RequestParams entity, Callback.CommonCallback callback) { + MyLog.network("请求链接:" + entity.getUri()); + //输出参数 +// MyLog.network("请求参数: " + entity.getBodyContent()); + entity.setMethod(method); + Callback.Cancelable cancelable = null; + if (callback instanceof Callback.Cancelable) { + cancelable = (Callback.Cancelable) callback; + } + HttpTask task = new HttpTask(entity, cancelable, callback); + + List headers = entity.getHeaders(); + for (BaseParams.Header header : headers) { + if (header.getKey().equals("Authorization") && !Global.isTokenAvailable()) { + MyUtil.login(() -> x.task().start(task)); + return null; + } + } + return x.task().start(task); + } + + @Override + public T getSync(RequestParams entity, Class resultType) throws Throwable { + return requestSync(HttpMethod.GET, entity, resultType); + } + + @Override + public T postSync(RequestParams entity, Class resultType) throws Throwable { + return requestSync(HttpMethod.POST, entity, resultType); + } + + @Override + public T requestSync(HttpMethod method, RequestParams entity, Class resultType) throws Throwable { + DefaultSyncCallback callback = new DefaultSyncCallback(resultType); + return requestSync(method, entity, callback); + } + + @Override + public T requestSync(HttpMethod method, RequestParams entity, Callback.TypedCallback callback) throws Throwable { + entity.setMethod(method); + HttpTask task = new HttpTask(entity, null, callback); + return x.task().startSync(task); + } + + private class DefaultSyncCallback implements Callback.TypedCallback { + + private final Class resultType; + + public DefaultSyncCallback(Class resultType) { + this.resultType = resultType; + } + + @Override + public Type getLoadType() { + return resultType; + } + + @Override + public void onSuccess(T result) { + + } + + @Override + public void onError(Throwable ex, boolean isOnCallback) { + + } + + @Override + public void onCancelled(CancelledException cex) { + + } + + @Override + public void onFinished() { + + } + } +} diff --git a/app/src/main/java/org/xutils/http/HttpMethod.java b/app/src/main/java/org/xutils/http/HttpMethod.java new file mode 100644 index 0000000..e521305 --- /dev/null +++ b/app/src/main/java/org/xutils/http/HttpMethod.java @@ -0,0 +1,46 @@ +package org.xutils.http; + +/** + * Created by wyouflf on 15/8/4. + * HTTP谓词枚举 + */ +public enum HttpMethod { + GET("GET"), + POST("POST"), + PUT("PUT"), + PATCH("PATCH"), + HEAD("HEAD"), + MOVE("MOVE"), + COPY("COPY"), + DELETE("DELETE"), + OPTIONS("OPTIONS"), + TRACE("TRACE"), + CONNECT("CONNECT"); + + private final String value; + + HttpMethod(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + + public static boolean permitsRetry(HttpMethod method) { + return method == GET; + } + + public static boolean permitsCache(HttpMethod method) { + return method == GET || method == POST; + } + + public static boolean permitsRequestBody(HttpMethod method) { + return method == null + || method == POST + || method == PUT + || method == PATCH + || method == DELETE; + } +} diff --git a/app/src/main/java/org/xutils/http/HttpTask.java b/app/src/main/java/org/xutils/http/HttpTask.java new file mode 100644 index 0000000..435b918 --- /dev/null +++ b/app/src/main/java/org/xutils/http/HttpTask.java @@ -0,0 +1,645 @@ +package org.xutils.http; + +import android.text.TextUtils; + +import org.xutils.common.Callback; +import org.xutils.common.task.AbsTask; +import org.xutils.common.task.Priority; +import org.xutils.common.task.PriorityExecutor; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.common.util.ParameterizedTypeUtil; +import org.xutils.ex.HttpException; +import org.xutils.ex.HttpRedirectException; +import org.xutils.http.app.HttpRetryHandler; +import org.xutils.http.app.RedirectHandler; +import org.xutils.http.app.RequestInterceptListener; +import org.xutils.http.app.RequestTracker; +import org.xutils.http.request.UriRequest; +import org.xutils.http.request.UriRequestFactory; +import org.xutils.x; + +import java.io.Closeable; +import java.io.File; +import java.lang.ref.WeakReference; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by wyouflf on 15/7/23. + * http 请求任务 + */ +public class HttpTask extends AbsTask implements ProgressHandler { + + // 请求相关 + private RequestParams params; + private UriRequest request; + private Type loadType; + private volatile boolean hasException = false; + private final Callback.CommonCallback callback; + + // 缓存控制 + private Object rawResult = null; + private volatile Boolean trustCache = null; + private final Object cacheLock = new Object(); + + // 扩展callback + private Callback.CacheCallback cacheCallback; + private Callback.PrepareCallback prepareCallback; + private Callback.ProgressCallback progressCallback; + private RequestInterceptListener requestInterceptListener; + + // 日志追踪 + private RequestTracker tracker; + + // 文件下载任务 + private final static AtomicInteger sCurrFileLoadCount = new AtomicInteger(0); + private static final HashMap>> + DOWNLOAD_TASK = new HashMap>>(1); + + // 线程池 + private final Executor executor; + private static final PriorityExecutor HTTP_EXECUTOR = new PriorityExecutor(5, true); + private static final PriorityExecutor CACHE_EXECUTOR = new PriorityExecutor(5, true); + + + public HttpTask(RequestParams params, Callback.Cancelable cancelHandler, + Callback.CommonCallback callback) { + super(cancelHandler); + + assert params != null; + assert callback != null; + + // set params & callback + this.params = params; + this.callback = callback; + if (callback instanceof Callback.CacheCallback) { + this.cacheCallback = (Callback.CacheCallback) callback; + } + if (callback instanceof Callback.PrepareCallback) { + this.prepareCallback = (Callback.PrepareCallback) callback; + } + if (callback instanceof Callback.ProgressCallback) { + this.progressCallback = (Callback.ProgressCallback) callback; + } + if (callback instanceof RequestInterceptListener) { + this.requestInterceptListener = (RequestInterceptListener) callback; + } + + // init tracker + { + RequestTracker customTracker = params.getRequestTracker(); + if (customTracker == null) { + if (callback instanceof RequestTracker) { + customTracker = (RequestTracker) callback; + } else { + customTracker = UriRequestFactory.getDefaultTracker(); + } + } + if (customTracker != null) { + tracker = new RequestTrackerWrapper(customTracker); + } + } + + // init executor + if (params.getExecutor() != null) { + this.executor = params.getExecutor(); + } else { + if (cacheCallback != null) { + this.executor = CACHE_EXECUTOR; + } else { + this.executor = HTTP_EXECUTOR; + } + } + } + + // 解析loadType + private void resolveLoadType() { + Class callBackType = callback.getClass(); + if (callback instanceof Callback.TypedCallback) { + loadType = ((Callback.TypedCallback) callback).getLoadType(); + } else if (callback instanceof Callback.PrepareCallback) { + loadType = ParameterizedTypeUtil.getParameterizedType(callBackType, Callback.PrepareCallback.class, 0); + } else { + loadType = ParameterizedTypeUtil.getParameterizedType(callBackType, Callback.CommonCallback.class, 0); + } + } + + // 初始化请求参数 + private UriRequest createNewRequest() throws Throwable { + // init request + params.init(); + UriRequest result = UriRequestFactory.getUriRequest(params, loadType); + result.setProgressHandler(this); + this.loadingUpdateMaxTimeSpan = params.getLoadingUpdateMaxTimeSpan(); + this.update(FLAG_REQUEST_CREATED, result); + return result; + } + + // 文件下载冲突检测 + private void checkDownloadTask() { + if (File.class == loadType) { + synchronized (DOWNLOAD_TASK) { + String downloadTaskKey = this.params.getSaveFilePath(); + /*{ + // 不处理缓存文件下载冲突, + // 缓存文件下载冲突会抛出FileLockedException异常, + // 回调方法中处理控制是否重新尝试下载. + }*/ + if (!TextUtils.isEmpty(downloadTaskKey)) { + WeakReference> taskRef = DOWNLOAD_TASK.get(downloadTaskKey); + if (taskRef != null) { + HttpTask task = taskRef.get(); + if (task != null) { + task.cancel(); + task.closeRequestSync(); + } + DOWNLOAD_TASK.remove(downloadTaskKey); + } + DOWNLOAD_TASK.put(downloadTaskKey, new WeakReference>(this)); + } // end if (!TextUtils.isEmpty(downloadTaskKey)) + + if (DOWNLOAD_TASK.size() > RequestParams.MAX_FILE_LOAD_WORKER) { + Iterator>>> + entryItr = DOWNLOAD_TASK.entrySet().iterator(); + while (entryItr.hasNext()) { + Map.Entry>> next = entryItr.next(); + WeakReference> value = next.getValue(); + if (value == null || value.get() == null) { + entryItr.remove(); + } + } + } + } // end synchronized + } + } + + @Override + @SuppressWarnings("unchecked") + protected ResultType doBackground() throws Throwable { + + if (this.isCancelled()) { + throw new Callback.CancelledException("cancelled before request"); + } + + // 初始化请求参数 + ResultType result = null; + resolveLoadType(); + request = createNewRequest(); + checkDownloadTask(); + // retry 初始化 + boolean retry = true; + int retryCount = 0; + Throwable exception = null; + HttpRetryHandler retryHandler = this.params.getHttpRetryHandler(); + if (retryHandler == null) { + retryHandler = new HttpRetryHandler(); + } + retryHandler.setMaxRetryCount(this.params.getMaxRetryCount()); + + if (this.isCancelled()) { + throw new Callback.CancelledException("cancelled before request"); + } + + // 检查缓存 + Object cacheResult = null; + if (cacheCallback != null && HttpMethod.permitsCache(params.getMethod())) { + // 尝试从缓存获取结果, 并为请求头加入缓存控制参数. + try { + clearRawResult(); + LogUtil.d("load cache: " + this.request.getRequestUri()); + rawResult = this.request.loadResultFromCache(); + } catch (Throwable ex) { + LogUtil.w("load disk cache error", ex); + } + + if (this.isCancelled()) { + clearRawResult(); + throw new Callback.CancelledException("cancelled before request"); + } + + if (rawResult != null) { + if (prepareCallback != null) { + try { + cacheResult = prepareCallback.prepare(rawResult); + } catch (Throwable ex) { + cacheResult = null; + LogUtil.w("prepare disk cache error", ex); + } finally { + clearRawResult(); + } + } else { + cacheResult = rawResult; + } + + if (this.isCancelled()) { + throw new Callback.CancelledException("cancelled before request"); + } + + if (cacheResult != null) { + // 同步等待是否信任缓存 + this.update(FLAG_CACHE, cacheResult); + synchronized (cacheLock) { + while (trustCache == null) { + try { + cacheLock.wait(); + } catch (InterruptedException iex) { + throw new Callback.CancelledException("cancelled before request"); + } catch (Throwable ignored) { + } + } + } + + // 处理完成 + if (trustCache) { + return null; + } + } + } + } + + if (trustCache == null) { + trustCache = false; + } + + if (cacheResult == null) { + this.request.clearCacheHeader(); + } + + // 判断请求的缓存策略 + if (callback instanceof Callback.ProxyCacheCallback) { + if (((Callback.ProxyCacheCallback) callback).onlyCache()) { + return null; + } + } + + // 发起请求 + retry = true; + while (retry) { + retry = false; + + try { + if (this.isCancelled()) { + throw new Callback.CancelledException("cancelled before request"); + } + + // 由loader发起请求, 拿到结果. + this.request.close(); // retry 前关闭上次请求 + + try { + clearRawResult(); + // 开始请求工作 + LogUtil.d("load: " + this.request.getRequestUri()); + RequestWorker requestWorker = new RequestWorker(); + requestWorker.request(); + if (requestWorker.ex != null) { + throw requestWorker.ex; + } + rawResult = requestWorker.result; + } catch (Throwable ex) { + clearRawResult(); + if (this.isCancelled()) { + throw new Callback.CancelledException("cancelled during request"); + } else { + throw ex; + } + } + + if (prepareCallback != null) { + + if (this.isCancelled()) { + throw new Callback.CancelledException("cancelled before request"); + } + + try { + result = (ResultType) prepareCallback.prepare(rawResult); + } finally { + clearRawResult(); + } + } else { + result = (ResultType) rawResult; + } + + // 保存缓存 + if (cacheCallback != null && HttpMethod.permitsCache(params.getMethod())) { + try { + this.request.save2Cache(); + } catch (Throwable ex) { + LogUtil.e("Error while storing the http cache.", ex); + } + } + + if (this.isCancelled()) { + throw new Callback.CancelledException("cancelled after request"); + } + } catch (HttpRedirectException redirectEx) { + retry = true; + LogUtil.w("Http Redirect:" + params.getUri()); + } catch (Throwable ex) { + switch (this.request.getResponseCode()) { + case 204: // empty content + case 205: // empty content + case 304: // disk cache is valid. + return null; + default: { + exception = ex; + if (this.isCancelled() && !(exception instanceof Callback.CancelledException)) { + exception = new Callback.CancelledException("canceled by user"); + } + retry = retryHandler.canRetry(this.request, exception, ++retryCount); + } + } + } + + } + + if (exception != null && result == null && !trustCache) { + hasException = true; + throw exception; + } + + return result; + } + + private static final int FLAG_REQUEST_CREATED = 1; + private static final int FLAG_CACHE = 2; + private static final int FLAG_PROGRESS = 3; + + @Override + @SuppressWarnings("unchecked") + protected void onUpdate(int flag, Object... args) { + switch (flag) { + case FLAG_REQUEST_CREATED: { + if (this.tracker != null) { + this.tracker.onRequestCreated((UriRequest) args[0]); + } + break; + } + case FLAG_CACHE: { + synchronized (cacheLock) { + try { + ResultType result = (ResultType) args[0]; + if (tracker != null) { + tracker.onCache(request, result); + } + trustCache = this.cacheCallback.onCache(result); + } catch (Throwable ex) { + trustCache = false; + callback.onError(ex, true); + } finally { + cacheLock.notifyAll(); + } + } + break; + } + case FLAG_PROGRESS: { + if (this.progressCallback != null && args.length == 3) { + try { + this.progressCallback.onLoading( + ((Number) args[0]).longValue(), + ((Number) args[1]).longValue(), + (Boolean) args[2]); + } catch (Throwable ex) { + callback.onError(ex, true); + } + } + break; + } + default: { + break; + } + } + } + + @Override + protected void onWaiting() { + if (tracker != null) { + tracker.onWaiting(params); + } + if (progressCallback != null) { + progressCallback.onWaiting(); + } + } + + @Override + protected void onStarted() { + if (tracker != null) { + tracker.onStart(params); + } + if (progressCallback != null) { + progressCallback.onStarted(); + } + } + + @Override + protected void onSuccess(ResultType result) { + if (hasException) return; + if (tracker != null) { + tracker.onSuccess(request, result); + } + callback.onSuccess(result); + } + + @Override + protected void onError(Throwable ex, boolean isCallbackError) { + if (tracker != null) { + tracker.onError(request, ex, isCallbackError); + } + callback.onError(ex, isCallbackError); + } + + + @Override + protected void onCancelled(Callback.CancelledException cex) { + if (tracker != null) { + tracker.onCancelled(request); + } + callback.onCancelled(cex); + } + + @Override + protected void onFinished() { + if (tracker != null) { + tracker.onFinished(request); + } + x.task().run(new Runnable() { + @Override + public void run() { + closeRequestSync(); + } + }); + callback.onFinished(); + } + + private void clearRawResult() { + if (rawResult instanceof Closeable) { + IOUtil.closeQuietly((Closeable) rawResult); + } + rawResult = null; + } + + @Override + protected void cancelWorks() { + x.task().run(new Runnable() { + @Override + public void run() { + closeRequestSync(); + } + }); + } + + @Override + protected boolean isCancelFast() { + return params.isCancelFast(); + } + + private void closeRequestSync() { + if (File.class == loadType) { + synchronized (sCurrFileLoadCount) { + sCurrFileLoadCount.notifyAll(); + } + } + clearRawResult(); + IOUtil.closeQuietly(request); + } + + @Override + public Executor getExecutor() { + return this.executor; + } + + @Override + public Priority getPriority() { + return params.getPriority(); + } + + // ############################### start: region implements ProgressHandler + private long lastUpdateTime; + private long loadingUpdateMaxTimeSpan = 300; // 300ms + + /** + * @return continue + */ + @Override + public boolean updateProgress(long total, long current, boolean forceUpdateUI) { + + if (isCancelled() || isFinished()) { + return false; + } + + if (progressCallback != null && request != null && current > 0) { + if (total < 0) { + total = -1; + } else if (total < current) { + total = current; + } + if (forceUpdateUI) { + lastUpdateTime = System.currentTimeMillis(); + this.update(FLAG_PROGRESS, total, current, request.isLoading()); + } else { + long currTime = System.currentTimeMillis(); + if (currTime - lastUpdateTime >= loadingUpdateMaxTimeSpan) { + lastUpdateTime = currTime; + this.update(FLAG_PROGRESS, total, current, request.isLoading()); + } + } + } + + return !isCancelled() && !isFinished(); + } + + // ############################### end: region implements ProgressHandler + + @Override + public String toString() { + return params.toString(); + } + + + /** + * 请求发送和加载数据线程. + * 该线程被join到HttpTask的工作线程去执行. + * 它的主要作用是为了能强行中断请求的链接过程; + * 并辅助限制同时下载文件的线程数. + */ + private final class RequestWorker { + /*private*/ Object result; + /*private*/ Throwable ex; + + private RequestWorker() { + } + + public void request() { + try { + boolean interrupted = false; + if (File.class == loadType) { + synchronized (sCurrFileLoadCount) { + while (sCurrFileLoadCount.get() >= RequestParams.MAX_FILE_LOAD_WORKER + && !HttpTask.this.isCancelled()) { + try { + sCurrFileLoadCount.wait(10); + } catch (InterruptedException iex) { + interrupted = true; + break; + } catch (Throwable ignored) { + } + } + } + sCurrFileLoadCount.incrementAndGet(); + } + + if (interrupted || HttpTask.this.isCancelled()) { + throw new Callback.CancelledException("cancelled before request" + (interrupted ? "(interrupted)" : "")); + } + + try { + request.setRequestInterceptListener(requestInterceptListener); + this.result = request.loadResult(); + } catch (Throwable ex) { + this.ex = ex; + } + + if (this.ex != null) { + throw this.ex; + } + } catch (Throwable ex) { + this.ex = ex; + if (ex instanceof HttpException) { + HttpException httpEx = (HttpException) ex; + int errorCode = httpEx.getCode(); + if (errorCode == 301 || errorCode == 302) { + RedirectHandler redirectHandler = params.getRedirectHandler(); + if (redirectHandler != null) { + try { + RequestParams redirectParams = redirectHandler.getRedirectParams(request); + if (redirectParams != null) { + if (redirectParams.getMethod() == null) { + redirectParams.setMethod(params.getMethod()); + } + // 开始重定向请求 + HttpTask.this.params = redirectParams; + HttpTask.this.request = createNewRequest(); + this.ex = new HttpRedirectException(errorCode, httpEx.getMessage(), httpEx.getResult()); + } + } catch (Throwable throwable) { + this.ex = ex; + } + } + } + } + } finally { + if (File.class == loadType) { + synchronized (sCurrFileLoadCount) { + sCurrFileLoadCount.decrementAndGet(); + sCurrFileLoadCount.notifyAll(); + } + } + } + } + } + +} diff --git a/app/src/main/java/org/xutils/http/ProgressHandler.java b/app/src/main/java/org/xutils/http/ProgressHandler.java new file mode 100644 index 0000000..fdaaa41 --- /dev/null +++ b/app/src/main/java/org/xutils/http/ProgressHandler.java @@ -0,0 +1,14 @@ +package org.xutils.http; + +/** + * 进度控制接口, updateProgress方式中ProgressCallback#onLoading. + * 默认最长间隔300毫秒调用一次. + * Author: wyouflf + * Time: 2014/05/23 + */ +public interface ProgressHandler { + /** + * @return continue + */ + boolean updateProgress(long total, long current, boolean forceUpdateUI); +} diff --git a/app/src/main/java/org/xutils/http/RequestParams.java b/app/src/main/java/org/xutils/http/RequestParams.java new file mode 100644 index 0000000..1d8a78c --- /dev/null +++ b/app/src/main/java/org/xutils/http/RequestParams.java @@ -0,0 +1,407 @@ +package org.xutils.http; + +import android.content.Context; +import android.text.TextUtils; + +import org.xutils.common.task.Priority; +import org.xutils.http.annotation.HttpRequest; +import org.xutils.http.app.DefaultParamsBuilder; +import org.xutils.http.app.DefaultRedirectHandler; +import org.xutils.http.app.HttpRetryHandler; +import org.xutils.http.app.ParamsBuilder; +import org.xutils.http.app.RedirectHandler; +import org.xutils.http.app.RequestTracker; +import org.xutils.x; + +import java.net.Proxy; +import java.util.concurrent.Executor; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSocketFactory; + +/** + * Created by wyouflf on 15/7/17. + * 网络请求参数实体 + */ +public class RequestParams extends BaseParams { + + public final static int MAX_FILE_LOAD_WORKER = 10; + private final static DefaultRedirectHandler DEFAULT_REDIRECT_HANDLER = new DefaultRedirectHandler(); + + // 注解及其扩展参数 + private HttpRequest httpRequest; + private String uri; + private final String[] signs; + private final String[] cacheKeys; + private ParamsBuilder builder; + private String buildUri; + private String buildCacheKey; + private SSLSocketFactory sslSocketFactory; + + // 扩展参数 + private Context context; + private Proxy proxy; // 代理 + private HostnameVerifier hostnameVerifier; // https域名校验 + private boolean useCookie = true; // 是否在请求过程中启用cookie + private String cacheDirName; // 缓存文件夹名称 + private long cacheSize; // 缓存文件夹大小 + private long cacheMaxAge; // 默认缓存存活时间, 单位:毫秒.(如果服务没有返回有效的max-age或Expires) + private Executor executor; // 自定义线程池 + private Priority priority = Priority.DEFAULT; // 请求优先级 + private int connectTimeout = 1000 * 15; // 连接超时时间 + private int readTimeout = 1000 * 15; // 读取超时时间 + private boolean autoResume = true; // 是否在下载是自动断点续传 + private boolean autoRename = false; // 是否根据头信息自动命名文件 + private int maxRetryCount = 2; // 最大请求错误重试次数 + private String saveFilePath; // 下载文件时文件保存的路径和文件名 + private boolean cancelFast = false; // 是否可以被立即停止, true: 为请求创建新的线程, 取消时请求线程被立即中断. + private int loadingUpdateMaxTimeSpan = 300; // 进度刷新最大间隔时间(ms) + private HttpRetryHandler httpRetryHandler; // 自定义HttpRetryHandler + private RequestTracker requestTracker; // 自定义日志记录接口. + private RedirectHandler redirectHandler = DEFAULT_REDIRECT_HANDLER; + + /** + * 使用空构造创建时必须, 必须是带有@HttpRequest注解的子类. + */ + public RequestParams() { + this(null, null, null, null); + } + + /** + * @param uri 不可为空 + */ + public RequestParams(String uri) { + this(uri, null, null, null); + } + + /** + * @param uri 不可为空 + * @param builder 用于自定义参数构建过程, 为空时使用{@link DefaultParamsBuilder} + * @param signs 自定义需要签名的字段, 会传给ParamsBuilder + * @param cacheKeys 自定义缓存关键key信息, 会传给ParamsBuilder + */ + public RequestParams(String uri, ParamsBuilder builder, String[] signs, String[] cacheKeys) { + if (uri != null && builder == null) { + builder = new DefaultParamsBuilder(); + } + this.uri = uri; + this.signs = signs; + this.cacheKeys = cacheKeys; + this.builder = builder; + this.context = x.app(); + } + + // invoke via HttpTask#createNewRequest + /*package*/ void init() throws Throwable { + if (!TextUtils.isEmpty(buildUri)) return; + + if (TextUtils.isEmpty(uri) && getHttpRequest() == null) { + throw new IllegalStateException("uri is empty && @HttpRequest == null"); + } + + // init params from entity + initEntityParams(); + + // build uri & cacheKey + buildUri = uri; + HttpRequest httpRequest = this.getHttpRequest(); + if (httpRequest != null) { + builder = httpRequest.builder().newInstance(); + buildUri = builder.buildUri(this, httpRequest); + builder.buildParams(this); + builder.buildSign(this, httpRequest.signs()); + if (sslSocketFactory == null) { + sslSocketFactory = builder.getSSLSocketFactory(); + } + } else if (this.builder != null) { + builder.buildParams(this); + builder.buildSign(this, signs); + if (sslSocketFactory == null) { + sslSocketFactory = builder.getSSLSocketFactory(); + } + } + } + + public String getUri() { + return TextUtils.isEmpty(buildUri) ? uri : buildUri; + } + + public void setUri(String uri) { + if (TextUtils.isEmpty(buildUri)) { + this.uri = uri; + } else { + this.buildUri = uri; + } + } + + public String getCacheKey() { + if (TextUtils.isEmpty(buildCacheKey) && builder != null) { + HttpRequest httpRequest = this.getHttpRequest(); + if (httpRequest != null) { + buildCacheKey = builder.buildCacheKey(this, httpRequest.cacheKeys()); + } else { + buildCacheKey = builder.buildCacheKey(this, cacheKeys); + } + } + return buildCacheKey; + } + + public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) { + this.sslSocketFactory = sslSocketFactory; + } + + public SSLSocketFactory getSslSocketFactory() { + return sslSocketFactory; + } + + public HostnameVerifier getHostnameVerifier() { + return hostnameVerifier; + } + + public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + } + + /** + * 是否在请求过程中启用cookie, 默认true. + */ + public boolean isUseCookie() { + return useCookie; + } + + /** + * 是否在请求过程中启用cookie, 默认true. + */ + public void setUseCookie(boolean useCookie) { + this.useCookie = useCookie; + } + + public Context getContext() { + return context; + } + + public void setContext(Context context) { + this.context = context; + } + + public Proxy getProxy() { + return proxy; + } + + public void setProxy(Proxy proxy) { + this.proxy = proxy; + } + + public Priority getPriority() { + return priority; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + if (connectTimeout > 0) { + this.connectTimeout = connectTimeout; + } + } + + public int getReadTimeout() { + return readTimeout; + } + + /** + * 注意get请求失败后默认会重试2次, 可以通过setMaxRetryCount(0)来防止get请求自动重试. + */ + public void setReadTimeout(int readTimeout) { + if (readTimeout > 0) { + this.readTimeout = readTimeout; + } + } + + public String getCacheDirName() { + return cacheDirName; + } + + public void setCacheDirName(String cacheDirName) { + this.cacheDirName = cacheDirName; + } + + public long getCacheSize() { + return cacheSize; + } + + public void setCacheSize(long cacheSize) { + this.cacheSize = cacheSize; + } + + /** + * 默认缓存存活时间, 单位:毫秒.(如果服务没有返回有效的max-age或Expires) + */ + public long getCacheMaxAge() { + return cacheMaxAge; + } + + /** + * 默认缓存存活时间, 单位:毫秒.(如果服务没有返回有效的max-age或Expires) + */ + public void setCacheMaxAge(long cacheMaxAge) { + this.cacheMaxAge = cacheMaxAge; + } + + /** + * 自定义线程池 + */ + public Executor getExecutor() { + return executor; + } + + /** + * 自定义线程池 + */ + public void setExecutor(Executor executor) { + this.executor = executor; + } + + /** + * 是否在下载是自动断点续传 + */ + public boolean isAutoResume() { + return autoResume; + } + + /** + * 设置是否在下载是自动断点续传 + */ + public void setAutoResume(boolean autoResume) { + this.autoResume = autoResume; + } + + /** + * 是否根据头信息自动命名文件 + */ + public boolean isAutoRename() { + return autoRename; + } + + /** + * 设置是否根据头信息自动命名文件 + */ + public void setAutoRename(boolean autoRename) { + this.autoRename = autoRename; + } + + /** + * 获取下载文件时文件保存的路径和文件名 + */ + public String getSaveFilePath() { + return saveFilePath; + } + + /** + * 设置下载文件时文件保存的路径和文件名 + */ + public void setSaveFilePath(String saveFilePath) { + this.saveFilePath = saveFilePath; + } + + public int getMaxRetryCount() { + return maxRetryCount; + } + + public void setMaxRetryCount(int maxRetryCount) { + this.maxRetryCount = maxRetryCount; + } + + /** + * 是否可以被立即停止. + * + * @return true: 为请求创建新的线程, 取消时请求线程被立即中断; false: 请求建立过程可能不被立即终止. + */ + public boolean isCancelFast() { + return cancelFast; + } + + /** + * 是否可以被立即停止. + * + * @param cancelFast true: 为请求创建新的线程, 取消时请求线程被立即中断; false: 请求建立过程可能不被立即终止. + */ + public void setCancelFast(boolean cancelFast) { + this.cancelFast = cancelFast; + } + + public int getLoadingUpdateMaxTimeSpan() { + return loadingUpdateMaxTimeSpan; + } + + /** + * 进度刷新最大间隔时间(默认300毫秒) + */ + public void setLoadingUpdateMaxTimeSpan(int loadingUpdateMaxTimeSpan) { + this.loadingUpdateMaxTimeSpan = loadingUpdateMaxTimeSpan; + } + + public HttpRetryHandler getHttpRetryHandler() { + return httpRetryHandler; + } + + public void setHttpRetryHandler(HttpRetryHandler httpRetryHandler) { + this.httpRetryHandler = httpRetryHandler; + } + + public RedirectHandler getRedirectHandler() { + return redirectHandler; + } + + /** + * 自定义重定向接口, 默认系统自动重定向. + */ + public void setRedirectHandler(RedirectHandler redirectHandler) { + this.redirectHandler = redirectHandler; + } + + public RequestTracker getRequestTracker() { + return requestTracker; + } + + public void setRequestTracker(RequestTracker requestTracker) { + this.requestTracker = requestTracker; + } + + private void initEntityParams() { + RequestParamsHelper.parseKV(this, this.getClass(), new RequestParamsHelper.ParseKVListener() { + @Override + public void onParseKV(String name, Object value) { + addParameter(name, value); + } + }); + } + + private boolean invokedGetHttpRequest = false; + + private HttpRequest getHttpRequest() { + if (httpRequest == null && !invokedGetHttpRequest) { + invokedGetHttpRequest = true; + Class thisCls = this.getClass(); + if (thisCls != RequestParams.class) { + httpRequest = thisCls.getAnnotation(HttpRequest.class); + } + } + + return httpRequest; + } + + @Override + public String toString() { + String url = this.getUri(); + String baseParamsStr = super.toString(); + return TextUtils.isEmpty(url) ? + baseParamsStr : + url + (url.contains("?") ? "&" : "?") + baseParamsStr; + } +} diff --git a/app/src/main/java/org/xutils/http/RequestParamsHelper.java b/app/src/main/java/org/xutils/http/RequestParamsHelper.java new file mode 100644 index 0000000..d6cf77b --- /dev/null +++ b/app/src/main/java/org/xutils/http/RequestParamsHelper.java @@ -0,0 +1,116 @@ +package org.xutils.http; + +import android.os.Parcelable; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.xutils.common.util.LogUtil; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Map; + +/** + * Created by wyouflf on 16/1/23. + */ +/*package*/ final class RequestParamsHelper { + + private static final ClassLoader BOOT_CL = String.class.getClassLoader(); + + private RequestParamsHelper() { + } + + /*package*/ interface ParseKVListener { + void onParseKV(String name, Object value); + } + + /*package*/ + static void parseKV(Object entity, Class type, ParseKVListener listener) { + if (entity == null || type == null || type == RequestParams.class || type == Object.class) { + return; + } else { + ClassLoader cl = type.getClassLoader(); + if (cl == null || cl == BOOT_CL) { + return; + } + } + + Field[] fields = type.getDeclaredFields(); + if (fields != null && fields.length > 0) { + for (Field field : fields) { + String name = field.getName(); + if (!Modifier.isTransient(field.getModifiers()) + && !"serialVersionUID".equals(name) + && field.getType() != Parcelable.Creator.class) { + try { + field.setAccessible(true); + Object value = field.get(entity); + if (value != null) { + listener.onParseKV(name, value); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + + parseKV(entity, type.getSuperclass(), listener); + } + + /*package*/ + static Object parseJSONObject(Object value) throws JSONException { + if (value == null) return null; + + Object result = value; + Class cls = value.getClass(); + if (cls.isArray()) { + JSONArray array = new JSONArray(); + int len = Array.getLength(value); + for (int i = 0; i < len; i++) { + array.put(parseJSONObject(Array.get(value, i))); + } + result = array; + } else if (value instanceof Iterable) { + JSONArray array = new JSONArray(); + Iterable list = (Iterable) value; + for (Object item : list) { + array.put(parseJSONObject(item)); + } + result = array; + } else if (value instanceof Map) { + final JSONObject jo = new JSONObject(); + Map map = (Map) value; + for (Map.Entry entry : map.entrySet()) { + Object k = entry.getKey(); + Object v = entry.getValue(); + if (k != null && v != null) { + jo.put(String.valueOf(k), parseJSONObject(v)); + } + } + result = jo; + } else { + ClassLoader cl = cls.getClassLoader(); + if (cl != null && cl != BOOT_CL) { + final JSONObject jo = new JSONObject(); + parseKV(value, cls, new ParseKVListener() { + @Override + public void onParseKV(String name, Object value) { + try { + value = parseJSONObject(value); + jo.put(name, value); + } catch (JSONException ex) { + throw new IllegalArgumentException("parse RequestParams to json failed", ex); + } + } + }); + result = jo; + } + } + + return result; + } + +} diff --git a/app/src/main/java/org/xutils/http/RequestTrackerWrapper.java b/app/src/main/java/org/xutils/http/RequestTrackerWrapper.java new file mode 100644 index 0000000..3b2c30e --- /dev/null +++ b/app/src/main/java/org/xutils/http/RequestTrackerWrapper.java @@ -0,0 +1,90 @@ +package org.xutils.http; + +import org.xutils.common.util.LogUtil; +import org.xutils.http.app.RequestTracker; +import org.xutils.http.request.UriRequest; + +/** + * Created by wyouflf on 15/11/4. + * Wrapper for tracker + */ +/*package*/ final class RequestTrackerWrapper implements RequestTracker { + + private final RequestTracker base; + + public RequestTrackerWrapper(RequestTracker base) { + this.base = base; + } + + @Override + public void onWaiting(RequestParams params) { + try { + base.onWaiting(params); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + @Override + public void onStart(RequestParams params) { + try { + base.onStart(params); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + @Override + public void onRequestCreated(UriRequest request) { + try { + base.onRequestCreated(request); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + @Override + public void onCache(UriRequest request, Object result) { + try { + base.onCache(request, result); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + @Override + public void onSuccess(UriRequest request, Object result) { + try { + base.onSuccess(request, result); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + @Override + public void onCancelled(UriRequest request) { + try { + base.onCancelled(request); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + @Override + public void onError(UriRequest request, Throwable ex, boolean isCallbackError) { + try { + base.onError(request, ex, isCallbackError); + } catch (Throwable exOnError) { + LogUtil.e(exOnError.getMessage(), exOnError); + } + } + + @Override + public void onFinished(UriRequest request) { + try { + base.onFinished(request); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } +} diff --git a/app/src/main/java/org/xutils/http/annotation/HttpRequest.java b/app/src/main/java/org/xutils/http/annotation/HttpRequest.java new file mode 100644 index 0000000..39e9626 --- /dev/null +++ b/app/src/main/java/org/xutils/http/annotation/HttpRequest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.http.annotation; + +import org.xutils.http.app.DefaultParamsBuilder; +import org.xutils.http.app.ParamsBuilder; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface HttpRequest { + + String host() default ""; + + String path(); + + Class builder() default DefaultParamsBuilder.class; + + String[] signs() default ""; + + String[] cacheKeys() default ""; +} \ No newline at end of file diff --git a/app/src/main/java/org/xutils/http/annotation/HttpResponse.java b/app/src/main/java/org/xutils/http/annotation/HttpResponse.java new file mode 100644 index 0000000..e882d97 --- /dev/null +++ b/app/src/main/java/org/xutils/http/annotation/HttpResponse.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.http.annotation; + +import org.xutils.http.app.ResponseParser; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface HttpResponse { + + Class parser(); + +} \ No newline at end of file diff --git a/app/src/main/java/org/xutils/http/app/DefaultParamsBuilder.java b/app/src/main/java/org/xutils/http/app/DefaultParamsBuilder.java new file mode 100644 index 0000000..65256b7 --- /dev/null +++ b/app/src/main/java/org/xutils/http/app/DefaultParamsBuilder.java @@ -0,0 +1,120 @@ +package org.xutils.http.app; + +import org.xutils.common.util.KeyValue; +import org.xutils.common.util.LogUtil; +import org.xutils.http.RequestParams; +import org.xutils.http.annotation.HttpRequest; + +import java.security.cert.X509Certificate; +import java.util.List; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +/** + * Created by wyouflf on 15/8/20. + * 默认参数构造器 + */ +public class DefaultParamsBuilder implements ParamsBuilder { + + public DefaultParamsBuilder() { + } + + /** + * 根据@HttpRequest构建请求的url + */ + @Override + public String buildUri(RequestParams params, HttpRequest httpRequest) throws Throwable { + return httpRequest.host() + "/" + httpRequest.path(); + } + + /** + * 根据注解的cacheKeys构建缓存的自定义key, + * 如果返回为空, 默认使用 url 和整个 query string 组成. + */ + @Override + public String buildCacheKey(RequestParams params, String[] cacheKeys) { + StringBuilder result = new StringBuilder(); + if (cacheKeys != null && cacheKeys.length > 0) { + result.append(params.getUri()).append("?"); + + // 添加cacheKeys对应的参数 + for (String key : cacheKeys) { + List kvList = params.getParams(key); + if (kvList != null && !kvList.isEmpty()) { + for (KeyValue kv : kvList) { + String value = kv.getValueStrOrNull(); + if (value != null) { + result.append(key).append("=").append(value).append("&"); + } + } + } + } + } + return result.toString(); + } + + /** + * 自定义SSLSocketFactory + */ + @Override + public SSLSocketFactory getSSLSocketFactory() throws Throwable { + return getTrustAllSSLSocketFactory(); + } + + /** + * 为请求添加通用参数或修改参数等操作 + */ + @Override + public void buildParams(RequestParams params) throws Throwable { + } + + /** + * 自定义参数签名 + */ + @Override + public void buildSign(RequestParams params, String[] signs) throws Throwable { + + } + + private static SSLSocketFactory trustAllSSlSocketFactory; + + public static SSLSocketFactory getTrustAllSSLSocketFactory() { + if (trustAllSSlSocketFactory == null) { + synchronized (DefaultParamsBuilder.class) { + if (trustAllSSlSocketFactory == null) { + + // 信任所有证书 + TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + @Override + public void checkClientTrusted(X509Certificate[] certs, String authType) { + LogUtil.d("checkClientTrusted:" + authType); + } + + @Override + public void checkServerTrusted(X509Certificate[] certs, String authType) { + LogUtil.d("checkServerTrusted:" + authType); + } + }}; + try { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustAllCerts, null); + trustAllSSlSocketFactory = sslContext.getSocketFactory(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + + return trustAllSSlSocketFactory; + } + +} diff --git a/app/src/main/java/org/xutils/http/app/DefaultRedirectHandler.java b/app/src/main/java/org/xutils/http/app/DefaultRedirectHandler.java new file mode 100644 index 0000000..a3f2f79 --- /dev/null +++ b/app/src/main/java/org/xutils/http/app/DefaultRedirectHandler.java @@ -0,0 +1,56 @@ +package org.xutils.http.app; + +import android.text.TextUtils; +import android.webkit.URLUtil; + +import org.xutils.http.HttpMethod; +import org.xutils.http.RequestParams; +import org.xutils.http.request.HttpRequest; +import org.xutils.http.request.UriRequest; + +public class DefaultRedirectHandler implements RedirectHandler { + @Override + public RequestParams getRedirectParams(UriRequest request) throws Throwable { + if (request instanceof HttpRequest) { + HttpRequest httpRequest = (HttpRequest) request; + RequestParams params = httpRequest.getParams(); + String location = httpRequest.getResponseHeader("Location"); + if (!TextUtils.isEmpty(location)) { + if (!URLUtil.isHttpsUrl(location) && !URLUtil.isHttpUrl(location)) { + String url = params.getUri(); + if (location.startsWith("/")) { + int pathIndex = url.indexOf("/", 8); + if (pathIndex != -1) { + url = url.substring(0, pathIndex); + } + } else { + int pathIndex = url.lastIndexOf("/"); + if (pathIndex >= 8) { + url = url.substring(0, pathIndex + 1); + } else { + url += "/"; + } + } + location = url + location; + } + params.setUri(location); + + + /* http 1.0 301 302 + * http 1.1 303 307 308 + */ + int code = request.getResponseCode(); + if (code == 301 || code == 302 || code == 303) { + params.clearParams(); + params.setMethod(HttpMethod.GET); + } /*else if (code == 307 || code == 308) { + // don't change the request method or params + }*/ + + return params; + } + } + + return null; + } +} diff --git a/app/src/main/java/org/xutils/http/app/HttpRetryHandler.java b/app/src/main/java/org/xutils/http/app/HttpRetryHandler.java new file mode 100644 index 0000000..36a3219 --- /dev/null +++ b/app/src/main/java/org/xutils/http/app/HttpRetryHandler.java @@ -0,0 +1,76 @@ +package org.xutils.http.app; + + +import org.json.JSONException; +import org.xutils.common.Callback; +import org.xutils.common.util.LogUtil; +import org.xutils.ex.HttpException; +import org.xutils.http.HttpMethod; +import org.xutils.http.request.UriRequest; + +import java.io.FileNotFoundException; +import java.net.MalformedURLException; +import java.net.NoRouteToHostException; +import java.net.PortUnreachableException; +import java.net.ProtocolException; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.HashSet; + +/** + * Author: wyouflf + * Time: 2014/05/30 + */ +public class HttpRetryHandler { + + protected int maxRetryCount = 2; + + protected static HashSet> blackList = new HashSet>(); + + static { + blackList.add(HttpException.class); + blackList.add(Callback.CancelledException.class); + blackList.add(MalformedURLException.class); + blackList.add(URISyntaxException.class); + blackList.add(NoRouteToHostException.class); + blackList.add(PortUnreachableException.class); + blackList.add(ProtocolException.class); + blackList.add(NullPointerException.class); + blackList.add(FileNotFoundException.class); + blackList.add(JSONException.class); + blackList.add(UnknownHostException.class); + blackList.add(IllegalArgumentException.class); + } + + public HttpRetryHandler() { + } + + public void setMaxRetryCount(int maxRetryCount) { + this.maxRetryCount = maxRetryCount; + } + + public boolean canRetry(UriRequest request, Throwable ex, int count) { + + LogUtil.w(ex.getMessage(), ex); + + if (count > maxRetryCount) { + LogUtil.w(request.toString()); + LogUtil.w("The Max Retry times has been reached!"); + return false; + } + + if (!HttpMethod.permitsRetry(request.getParams().getMethod())) { + LogUtil.w(request.toString()); + LogUtil.w("The Request Method can not be retried."); + return false; + } + + if (blackList.contains(ex.getClass())) { + LogUtil.w(request.toString()); + LogUtil.w("The Exception can not be retried."); + return false; + } + + return true; + } +} diff --git a/app/src/main/java/org/xutils/http/app/ParamsBuilder.java b/app/src/main/java/org/xutils/http/app/ParamsBuilder.java new file mode 100644 index 0000000..64de428 --- /dev/null +++ b/app/src/main/java/org/xutils/http/app/ParamsBuilder.java @@ -0,0 +1,40 @@ +package org.xutils.http.app; + +import org.xutils.http.RequestParams; +import org.xutils.http.annotation.HttpRequest; + +import javax.net.ssl.SSLSocketFactory; + +/** + * Created by wyouflf on 15/8/20. + *

+ * {@link HttpRequest} 注解的参数构建的模板接口 + */ +public interface ParamsBuilder { + + /** + * 根据@HttpRequest构建请求的url + */ + String buildUri(RequestParams params, HttpRequest httpRequest) throws Throwable; + + /** + * 根据注解的cacheKeys构建缓存的自定义key, + * 如果返回为空, 默认使用 url 和整个 query string 组成. + */ + String buildCacheKey(RequestParams params, String[] cacheKeys); + + /** + * 自定义SSLSocketFactory + */ + SSLSocketFactory getSSLSocketFactory() throws Throwable; + + /** + * 为请求添加通用参数等操作 + */ + void buildParams(RequestParams params) throws Throwable; + + /** + * 自定义参数签名 + */ + void buildSign(RequestParams params, String[] signs) throws Throwable; +} diff --git a/app/src/main/java/org/xutils/http/app/RedirectHandler.java b/app/src/main/java/org/xutils/http/app/RedirectHandler.java new file mode 100644 index 0000000..c2c72a7 --- /dev/null +++ b/app/src/main/java/org/xutils/http/app/RedirectHandler.java @@ -0,0 +1,19 @@ +package org.xutils.http.app; + +import org.xutils.http.RequestParams; +import org.xutils.http.request.UriRequest; + +/** + * Created by wyouflf on 15/11/12. + * 请求重定向控制接口 + */ +public interface RedirectHandler { + + /** + * 根据请求信息返回自定义重定向的请求参数 + * + * @param request 原始请求 + * @return 返回不为null时进行重定向 + */ + RequestParams getRedirectParams(UriRequest request) throws Throwable; +} diff --git a/app/src/main/java/org/xutils/http/app/RequestInterceptListener.java b/app/src/main/java/org/xutils/http/app/RequestInterceptListener.java new file mode 100644 index 0000000..adad613 --- /dev/null +++ b/app/src/main/java/org/xutils/http/app/RequestInterceptListener.java @@ -0,0 +1,25 @@ +package org.xutils.http.app; + + +import org.xutils.http.request.UriRequest; + +/** + * Created by wyouflf on 15/11/10. + * 拦截请求响应(在后台线程工作). + *

+ * 用法: + * 1. 请求的callback参数同时实现RequestInterceptListener + * 2. 或者使用 @HttpRequest 注解实现ParamsBuilder接口 + */ +public interface RequestInterceptListener { + + /** + * 检查请求参数等处理 + */ + void beforeRequest(UriRequest request) throws Throwable; + + /** + * 检查请求相应头等处理 + */ + void afterRequest(UriRequest request) throws Throwable; +} \ No newline at end of file diff --git a/app/src/main/java/org/xutils/http/app/RequestTracker.java b/app/src/main/java/org/xutils/http/app/RequestTracker.java new file mode 100644 index 0000000..124f0e9 --- /dev/null +++ b/app/src/main/java/org/xutils/http/app/RequestTracker.java @@ -0,0 +1,35 @@ +package org.xutils.http.app; + +import org.xutils.http.RequestParams; +import org.xutils.http.request.UriRequest; + +/** + * Created by wyouflf on 15/9/10. + * 请求过程追踪, 适合用来记录请求日志. + * 所有回调方法都在主线程进行. + *

+ * 用法: + * 1. 将RequestTracker实例设置给请求参数RequestParams. + * 2. 请的callback参数同时实现RequestTracker接口; + * 3. 注册给UriRequestFactory的默认RequestTracker. + * 注意: 请求回调RequestTracker时优先级按照上面的顺序, + * 找到一个RequestTracker的实现会忽略其他. + */ +public interface RequestTracker { + + void onWaiting(RequestParams params); + + void onStart(RequestParams params); + + void onRequestCreated(UriRequest request); + + void onCache(UriRequest request, Object result); + + void onSuccess(UriRequest request, Object result); + + void onCancelled(UriRequest request); + + void onError(UriRequest request, Throwable ex, boolean isCallbackError); + + void onFinished(UriRequest request); +} diff --git a/app/src/main/java/org/xutils/http/app/ResponseParser.java b/app/src/main/java/org/xutils/http/app/ResponseParser.java new file mode 100644 index 0000000..f028988 --- /dev/null +++ b/app/src/main/java/org/xutils/http/app/ResponseParser.java @@ -0,0 +1,23 @@ +package org.xutils.http.app; + + +import java.lang.reflect.Type; + +/** + * Created by wyouflf on 15/8/4. + * {@link org.xutils.http.annotation.HttpResponse} 注解的返回值转换模板 + * + * @param 支持String, byte[], JSONObject, JSONArray, InputStream + */ +public interface ResponseParser extends RequestInterceptListener { + + /** + * 转换result为resultType类型的对象 + * + * @param resultType 返回值类型(可能带有泛型信息) + * @param resultClass 返回值类型 + * @param result 网络返回数据(支持String, byte[], JSONObject, JSONArray, InputStream) + * @return 请求结果, 类型为resultType + */ + Object parse(Type resultType, Class resultClass, ResponseDataType result) throws Throwable; +} diff --git a/app/src/main/java/org/xutils/http/body/FileBody.java b/app/src/main/java/org/xutils/http/body/FileBody.java new file mode 100644 index 0000000..5170001 --- /dev/null +++ b/app/src/main/java/org/xutils/http/body/FileBody.java @@ -0,0 +1,60 @@ +package org.xutils.http.body; + +import android.net.Uri; +import android.text.TextUtils; + +import org.xutils.common.util.LogUtil; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.HttpURLConnection; + +/** + * Created by wyouflf on 15/8/13. + */ +public class FileBody extends InputStreamBody { + + private File file; + private String contentType; + + public FileBody(File file) throws IOException { + this(file, null); + } + + public FileBody(File file, String contentType) throws IOException { + super(new FileInputStream(file)); + this.file = file; + this.contentType = contentType; + } + + @Override + public void setContentType(String contentType) { + this.contentType = contentType; + } + + @Override + public String getContentType() { + if (TextUtils.isEmpty(contentType)) { + contentType = getFileContentType(file); + } + return contentType; + } + + public static String getFileContentType(File file) { + String filename = file.getName(); + String contentType = null; + try { + filename = Uri.encode(filename, "-![.:/,?&=]"); + contentType = HttpURLConnection.guessContentTypeFromName(filename); + } catch (Exception e) { + LogUtil.e(e.toString()); + } + if (TextUtils.isEmpty(contentType)) { + contentType = "application/octet-stream"; + } else { + contentType = contentType.replaceFirst("\\/jpg$", "/jpeg"); + } + return contentType; + } +} diff --git a/app/src/main/java/org/xutils/http/body/InputStreamBody.java b/app/src/main/java/org/xutils/http/body/InputStreamBody.java new file mode 100644 index 0000000..2081afa --- /dev/null +++ b/app/src/main/java/org/xutils/http/body/InputStreamBody.java @@ -0,0 +1,98 @@ +package org.xutils.http.body; + +import android.text.TextUtils; + +import org.xutils.common.Callback; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.http.ProgressHandler; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + + +/** + * Author: wyouflf + * Time: 2014/05/30 + */ +public class InputStreamBody implements ProgressBody { + + private InputStream content; + private String contentType; + + private final long total; + private long current = 0; + + private ProgressHandler callBackHandler; + + public InputStreamBody(InputStream inputStream) { + this(inputStream, null); + } + + public InputStreamBody(InputStream inputStream, String contentType) { + this.content = inputStream; + this.contentType = contentType; + this.total = getInputStreamLength(inputStream); + } + + @Override + public void setProgressHandler(ProgressHandler progressHandler) { + this.callBackHandler = progressHandler; + } + + @Override + public long getContentLength() { + return total; + } + + @Override + public void setContentType(String contentType) { + this.contentType = contentType; + } + + @Override + public String getContentType() { + return TextUtils.isEmpty(contentType) ? "application/octet-stream" : contentType; + } + + @Override + public void writeTo(OutputStream out) throws IOException { + if (callBackHandler != null && !callBackHandler.updateProgress(total, current, true)) { + throw new Callback.CancelledException("upload stopped!"); + } + + byte[] buffer = new byte[4096]; + try { + int len = 0; + while ((len = content.read(buffer)) != -1) { + out.write(buffer, 0, len); + current += len; + if (callBackHandler != null && !callBackHandler.updateProgress(total, current, false)) { + throw new Callback.CancelledException("upload stopped!"); + } + } + out.flush(); + + if (callBackHandler != null) { + callBackHandler.updateProgress(total, current, true); + } + } finally { + IOUtil.closeQuietly(content); + } + } + + public static long getInputStreamLength(InputStream inputStream) { + try { + if (inputStream instanceof FileInputStream || + inputStream instanceof ByteArrayInputStream) { + return inputStream.available(); + } + } catch (Throwable ex) { + LogUtil.w(ex.getMessage(), ex); + } + return -1L; + } +} diff --git a/app/src/main/java/org/xutils/http/body/MultipartBody.java b/app/src/main/java/org/xutils/http/body/MultipartBody.java new file mode 100644 index 0000000..befe738 --- /dev/null +++ b/app/src/main/java/org/xutils/http/body/MultipartBody.java @@ -0,0 +1,264 @@ +package org.xutils.http.body; + + +import android.text.TextUtils; + +import org.xutils.common.Callback; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.KeyValue; +import org.xutils.http.BaseParams.BodyItemWrapper; +import org.xutils.http.ProgressHandler; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Author: wyouflf + * Time: 2014/05/30 + */ +public class MultipartBody implements ProgressBody { + + private static byte[] BOUNDARY_PREFIX_BYTES = "--------7da3d81520810".getBytes(); + private static byte[] END_BYTES = "\r\n".getBytes(); + private static byte[] TWO_DASHES_BYTES = "--".getBytes(); + private byte[] boundaryPostfixBytes; + private String contentType; // multipart/subtype; boundary=xxx... + private String charset = "UTF-8"; + + private List multipartParams; + private long total = 0; + private long current = 0; + + public MultipartBody(List multipartParams, String charset) { + if (!TextUtils.isEmpty(charset)) { + this.charset = charset; + } + this.multipartParams = multipartParams; + generateContentType(); + + // calc total + CounterOutputStream counter = new CounterOutputStream(); + try { + this.writeTo(counter); + this.total = counter.total.get(); + } catch (IOException e) { + this.total = -1; + } + } + + private ProgressHandler callBackHandler; + + @Override + public void setProgressHandler(ProgressHandler progressHandler) { + this.callBackHandler = progressHandler; + } + + private void generateContentType() { + String boundaryPostfix = Double.toHexString(Math.random() * 0xFFFF); + boundaryPostfixBytes = boundaryPostfix.getBytes(); + contentType = "multipart/form-data; boundary=" + new String(BOUNDARY_PREFIX_BYTES) + boundaryPostfix; + } + + @Override + public long getContentLength() { + return total; + } + + /** + * only change subType: + * "multipart/subType; boundary=xxx..." + * + * @param subType "form-data" or "related" + */ + @Override + public void setContentType(String subType) { + if (TextUtils.isEmpty(subType)) return; + int index = contentType.indexOf(";"); + this.contentType = "multipart/" + subType + contentType.substring(index); + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public void writeTo(OutputStream out) throws IOException { + + if (callBackHandler != null && !callBackHandler.updateProgress(total, current, true)) { + throw new Callback.CancelledException("upload stopped!"); + } + + for (KeyValue entry : multipartParams) { + writeEntry(out, entry); + } + writeLine(out, TWO_DASHES_BYTES, BOUNDARY_PREFIX_BYTES, boundaryPostfixBytes, TWO_DASHES_BYTES); + out.flush(); + + if (callBackHandler != null) { + callBackHandler.updateProgress(total, current, true); + } + } + + /** + * 写入multipart中的一项 + */ + private void writeEntry(OutputStream out, KeyValue entry) throws IOException { + String name = entry.key; + Object value = entry.value; + if (TextUtils.isEmpty(name) || value == null) return; + + writeLine(out, TWO_DASHES_BYTES, BOUNDARY_PREFIX_BYTES, boundaryPostfixBytes); + + String fileName = ""; + String contentType = null; + if (entry instanceof BodyItemWrapper) { + BodyItemWrapper wrapper = (BodyItemWrapper) entry; + fileName = wrapper.fileName; + contentType = wrapper.contentType; + } + + if (value instanceof File) { + File file = (File) value; + if (TextUtils.isEmpty(fileName)) { + fileName = file.getName(); + } + if (TextUtils.isEmpty(contentType)) { + contentType = FileBody.getFileContentType(file); + } + writeLine(out, buildContentDisposition(name, fileName, charset)); + writeLine(out, buildContentType(value, contentType, charset)); + writeLine(out); // 内容前空一行 + writeFile(out, file); + writeLine(out); + } else { + writeLine(out, buildContentDisposition(name, fileName, charset)); + writeLine(out, buildContentType(value, contentType, charset)); + writeLine(out); // 内容前空一行 + if (value instanceof InputStream) { + writeStreamAndCloseIn(out, (InputStream) value); + writeLine(out); + } else { + byte[] content; + if (value instanceof byte[]) { + content = (byte[]) value; + } else { + content = entry.getValueStrOrEmpty().getBytes(charset); + } + writeLine(out, content); + current += content.length; + if (callBackHandler != null && !callBackHandler.updateProgress(total, current, false)) { + throw new Callback.CancelledException("upload stopped!"); + } + } + } + } + + private void writeLine(OutputStream out, byte[]... bs) throws IOException { + if (bs != null) { + for (byte[] b : bs) { + out.write(b); + } + } + out.write(END_BYTES); + } + + private void writeFile(OutputStream out, File file) throws IOException { + if (out instanceof CounterOutputStream) { + ((CounterOutputStream) out).addFile(file); + } else { + writeStreamAndCloseIn(out, new FileInputStream(file)); + } + } + + private void writeStreamAndCloseIn(OutputStream out, InputStream in) throws IOException { + if (out instanceof CounterOutputStream) { + ((CounterOutputStream) out).addStream(in); + } else { + try { + int len; + byte[] buf = new byte[4096]; + while ((len = in.read(buf)) >= 0) { + out.write(buf, 0, len); + current += len; + if (callBackHandler != null && !callBackHandler.updateProgress(total, current, false)) { + throw new Callback.CancelledException("upload stopped!"); + } + } + } finally { + IOUtil.closeQuietly(in); + } + } + } + + private static byte[] buildContentDisposition(String name, String fileName, String charset) throws UnsupportedEncodingException { + StringBuilder result = new StringBuilder("Content-Disposition: form-data"); + result.append("; name=\"").append(name.replace("\"", "\\\"")).append("\""); + if (!TextUtils.isEmpty(fileName)) { + result.append("; filename=\"").append(fileName.replace("\"", "\\\"")).append("\""); + } + return result.toString().getBytes(charset); + } + + private static byte[] buildContentType(Object value, String contentType, String charset) throws UnsupportedEncodingException { + StringBuilder result = new StringBuilder("Content-Type: "); + if (TextUtils.isEmpty(contentType)) { + if (value instanceof String) { + contentType = "text/plain; charset=" + charset; + } else { + contentType = "application/octet-stream"; + } + } else { + contentType = contentType.replaceFirst("\\/jpg$", "/jpeg"); + } + result.append(contentType); + return result.toString().getBytes(charset); + } + + private class CounterOutputStream extends OutputStream { + + final AtomicLong total = new AtomicLong(0L); + + public CounterOutputStream() { + } + + public void addFile(File file) { + if (total.get() == -1L) return; + total.addAndGet(file.length()); + } + + public void addStream(InputStream inputStream) { + if (total.get() == -1L) return; + long length = InputStreamBody.getInputStreamLength(inputStream); + if (length > 0) { + total.addAndGet(length); + } else { + total.set(-1L); + } + } + + @Override + public void write(int oneByte) throws IOException { + if (total.get() == -1L) return; + total.incrementAndGet(); + } + + @Override + public void write(byte[] buffer) throws IOException { + if (total.get() == -1L) return; + total.addAndGet(buffer.length); + } + + @Override + public void write(byte[] buffer, int offset, int count) throws IOException { + if (total.get() == -1L) return; + total.addAndGet(count); + } + } +} diff --git a/app/src/main/java/org/xutils/http/body/ProgressBody.java b/app/src/main/java/org/xutils/http/body/ProgressBody.java new file mode 100644 index 0000000..51be474 --- /dev/null +++ b/app/src/main/java/org/xutils/http/body/ProgressBody.java @@ -0,0 +1,11 @@ +package org.xutils.http.body; + + +import org.xutils.http.ProgressHandler; + +/** + * Created by wyouflf on 15/8/13. + */ +public interface ProgressBody extends RequestBody { + void setProgressHandler(ProgressHandler progressHandler); +} diff --git a/app/src/main/java/org/xutils/http/body/RequestBody.java b/app/src/main/java/org/xutils/http/body/RequestBody.java new file mode 100644 index 0000000..e698ea5 --- /dev/null +++ b/app/src/main/java/org/xutils/http/body/RequestBody.java @@ -0,0 +1,18 @@ +package org.xutils.http.body; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Created by wyouflf on 15/10/29. + */ +public interface RequestBody { + + long getContentLength(); + + void setContentType(String contentType); + + String getContentType(); + + void writeTo(OutputStream out) throws IOException; +} diff --git a/app/src/main/java/org/xutils/http/body/StringBody.java b/app/src/main/java/org/xutils/http/body/StringBody.java new file mode 100644 index 0000000..51a8fd6 --- /dev/null +++ b/app/src/main/java/org/xutils/http/body/StringBody.java @@ -0,0 +1,46 @@ +package org.xutils.http.body; + +import android.text.TextUtils; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +/** + * Author: wyouflf + * Time: 2014/05/30 + */ +public class StringBody implements RequestBody { + + private byte[] content; + private String contentType; + private String charset = "UTF-8"; + + public StringBody(String str, String charset) throws UnsupportedEncodingException { + if (!TextUtils.isEmpty(charset)) { + this.charset = charset; + } + this.content = str.getBytes(this.charset); + } + + @Override + public long getContentLength() { + return content.length; + } + + @Override + public void setContentType(String contentType) { + this.contentType = contentType; + } + + @Override + public String getContentType() { + return TextUtils.isEmpty(contentType) ? "application/json;charset=" + charset : contentType; + } + + @Override + public void writeTo(OutputStream out) throws IOException { + out.write(content); + out.flush(); + } +} diff --git a/app/src/main/java/org/xutils/http/body/UrlEncodedBody.java b/app/src/main/java/org/xutils/http/body/UrlEncodedBody.java new file mode 100644 index 0000000..999dad7 --- /dev/null +++ b/app/src/main/java/org/xutils/http/body/UrlEncodedBody.java @@ -0,0 +1,67 @@ +package org.xutils.http.body; + +import android.text.TextUtils; + +import org.xutils.common.util.KeyValue; +import org.xutils.common.util.LogUtil; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.URLEncoder; +import java.util.List; + +/** + * Author: wyouflf + * Time: 2014/05/30 + */ +public class UrlEncodedBody implements RequestBody { + + private byte[] content; + private String charset = "UTF-8"; + + public UrlEncodedBody(List params, String charset) throws IOException { + if (!TextUtils.isEmpty(charset)) { + this.charset = charset; + } + StringBuilder contentSb = new StringBuilder(); + if (params != null) { + for (KeyValue kv : params) { + String name = kv.key; + String value = kv.getValueStrOrNull(); + if (!TextUtils.isEmpty(name) && value != null) { + if (contentSb.length() > 0) { + contentSb.append("&"); + } + contentSb.append(URLEncoder.encode(name, this.charset).replaceAll("\\+", "%20")) + .append("=") + .append(URLEncoder.encode(value, this.charset).replaceAll("\\+", "%20")); + } + } + } + + this.content = contentSb.toString().getBytes(this.charset); + } + + @Override + public long getContentLength() { + return content.length; + } + + @Override + public void setContentType(String contentType) { + if (!TextUtils.isEmpty(contentType)) { + LogUtil.w("ignored Content-Type: " + contentType); + } + } + + @Override + public String getContentType() { + return "application/x-www-form-urlencoded;charset=" + charset; + } + + @Override + public void writeTo(OutputStream sink) throws IOException { + sink.write(this.content); + sink.flush(); + } +} diff --git a/app/src/main/java/org/xutils/http/cookie/CookieEntity.java b/app/src/main/java/org/xutils/http/cookie/CookieEntity.java new file mode 100644 index 0000000..0dc8905 --- /dev/null +++ b/app/src/main/java/org/xutils/http/cookie/CookieEntity.java @@ -0,0 +1,117 @@ +package org.xutils.http.cookie; + +import android.text.TextUtils; + +import org.xutils.db.annotation.Column; +import org.xutils.db.annotation.Table; + +import java.net.HttpCookie; +import java.net.URI; + +/** + * Created by wyouflf on 15/8/20. + * 数据库中的cookie实体 + */ +@Table(name = "cookie", + onCreated = "CREATE UNIQUE INDEX index_cookie_unique ON cookie(\"name\",\"domain\",\"path\")") +/*package*/ final class CookieEntity { + + // ~ 100 year + private static final long MAX_EXPIRY = System.currentTimeMillis() + 1000L * 60L * 60L * 24L * 30L * 12L * 100L; + + @Column(name = "id", isId = true) + private long id; + + @Column(name = "uri") + private String uri; // cookie add by this uri. + + @Column(name = "name") + private String name; + @Column(name = "value") + private String value; + @Column(name = "comment") + private String comment; + @Column(name = "commentURL") + private String commentURL; + @Column(name = "discard") + private boolean discard; + @Column(name = "domain") + private String domain; + @Column(name = "expiry") + private long expiry = MAX_EXPIRY; + @Column(name = "path") + private String path; + @Column(name = "portList") + private String portList; + @Column(name = "secure") + private boolean secure; + @Column(name = "version") + private int version = 1; + + public CookieEntity() { + } + + public CookieEntity(URI uri, HttpCookie cookie) { + this.uri = uri == null ? null : uri.toString(); + this.name = cookie.getName(); + this.value = cookie.getValue(); + this.comment = cookie.getComment(); + this.commentURL = cookie.getCommentURL(); + this.discard = cookie.getDiscard(); + this.domain = cookie.getDomain(); + long maxAge = cookie.getMaxAge(); + if (maxAge > 0) { + this.expiry = (maxAge * 1000L) + System.currentTimeMillis(); + if (this.expiry < 0L) { // 计算溢出? + this.expiry = MAX_EXPIRY; + } + } else { + this.expiry = -1L; + } + this.path = cookie.getPath(); + if (!TextUtils.isEmpty(path) && path.length() > 1 && path.endsWith("/")) { + this.path = path.substring(0, path.length() - 1); + } + this.portList = cookie.getPortlist(); + this.secure = cookie.getSecure(); + this.version = cookie.getVersion(); + } + + public HttpCookie toHttpCookie() { + HttpCookie cookie = new HttpCookie(name, value); + cookie.setComment(comment); + cookie.setCommentURL(commentURL); + cookie.setDiscard(discard); + cookie.setDomain(domain); + if (expiry == -1L) { + cookie.setMaxAge(-1L); + } else { + cookie.setMaxAge((expiry - System.currentTimeMillis()) / 1000L); + } + cookie.setPath(path); + cookie.setPortlist(portList); + cookie.setSecure(secure); + cookie.setVersion(version); + return cookie; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public boolean isExpired() { + return expiry != -1L && expiry < System.currentTimeMillis(); + } +} diff --git a/app/src/main/java/org/xutils/http/cookie/DbCookieStore.java b/app/src/main/java/org/xutils/http/cookie/DbCookieStore.java new file mode 100644 index 0000000..53ce008 --- /dev/null +++ b/app/src/main/java/org/xutils/http/cookie/DbCookieStore.java @@ -0,0 +1,328 @@ +package org.xutils.http.cookie; + +import android.text.TextUtils; + +import org.xutils.DbManager; +import org.xutils.common.task.PriorityExecutor; +import org.xutils.common.util.LogUtil; +import org.xutils.config.DbConfigs; +import org.xutils.db.Selector; +import org.xutils.db.sqlite.WhereBuilder; +import org.xutils.db.table.DbModel; +import org.xutils.x; + +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * Created by wyouflf on 15/8/20. + * 基于数据库的CookieStore实现. + */ +public enum DbCookieStore implements CookieStore { + + INSTANCE; + + private DbManager db; + private final Executor trimExecutor = new PriorityExecutor(1, true); + private static final int LIMIT_COUNT = 5000; // 限制最多5000条数据 + + private long lastTrimTime = 0L; + private static final long TRIM_TIME_SPAN = 1000; + + DbCookieStore() { + x.task().run(new Runnable() { + @Override + public void run() { + tryInit(); + } + }); + } + + private void tryInit() { + if (db == null) { + synchronized (this) { + if (db == null) { + try { + db = x.getDb(DbConfigs.COOKIE.getConfig()); + db.delete(CookieEntity.class, + WhereBuilder.b("expiry", "=", -1L)); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + } + + /** + * Add one cookie into cookie store. + */ + @Override + public void add(URI uri, HttpCookie cookie) { + if (cookie == null) { + return; + } + + tryInit(); + + uri = getEffectiveURI(uri); + + try { + db.replace(new CookieEntity(uri, cookie)); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + trimSize(); + } + + + /** + * Get all cookies, which: + * 1) given uri domain-matches with, or, associated with + * 2) given uri when added to the cookie store. + * 3) not expired. + * See RFC 2965 sec. 3.3.4 for more detail. + */ + @Override + public List get(URI uri) { + // argument can't be null + if (uri == null) { + throw new NullPointerException("uri is null"); + } + + tryInit(); + + uri = getEffectiveURI(uri); + + List rt = new ArrayList(); + + try { + + Selector selector = db.selector(CookieEntity.class); + + WhereBuilder where = WhereBuilder.b(); + + String host = uri.getHost(); + if (!TextUtils.isEmpty(host)) { + WhereBuilder subWhere = WhereBuilder.b("domain", "=", host).or("domain", "=", "." + host); + int firstDot = host.indexOf("."); + int lastDot = host.lastIndexOf("."); + if (firstDot > 0 && lastDot > firstDot) { + String domain = host.substring(firstDot, host.length()); + if (!TextUtils.isEmpty(domain)) { + subWhere.or("domain", "=", domain); + } + } + where.and(subWhere); + } + + String path = uri.getPath(); + if (!TextUtils.isEmpty(path)) { + WhereBuilder subWhere = WhereBuilder.b("path", "=", path) + .or("path", "=", "/").or("path", "=", null); + int lastSplit = path.lastIndexOf("/"); + while (lastSplit > 0) { + path = path.substring(0, lastSplit); + subWhere.or("path", "=", path); + lastSplit = path.lastIndexOf("/"); + } + + where.and(subWhere); + } + + where.or("uri", "=", uri.toString()); + + List cookieEntityList = selector.where(where).findAll(); + if (cookieEntityList != null) { + for (CookieEntity cookieEntity : cookieEntityList) { + if (!cookieEntity.isExpired()) { + rt.add(cookieEntity.toHttpCookie()); + } + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + return rt; + } + + /** + * Get all cookies in cookie store, except those have expired + */ + @Override + public List getCookies() { + tryInit(); + + List rt = new ArrayList(); + + try { + List cookieEntityList = db.findAll(CookieEntity.class); + if (cookieEntityList != null) { + for (CookieEntity cookieEntity : cookieEntityList) { + if (!cookieEntity.isExpired()) { + rt.add(cookieEntity.toHttpCookie()); + } + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + + return rt; + } + + /** + * Get all URIs, which are associated with at least one cookie + * of this cookie store. + */ + @Override + public List getURIs() { + tryInit(); + + List uris = new ArrayList(); + + try { + List uriList = + db.selector(CookieEntity.class).select("uri").findAll(); + if (uriList != null) { + for (DbModel model : uriList) { + String uri = model.getString("uri"); + if (!TextUtils.isEmpty(uri)) { + try { + uris.add(new URI(uri)); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + try { + db.delete(CookieEntity.class, WhereBuilder.b("uri", "=", uri)); + } catch (Throwable throwable) { + LogUtil.e(throwable.getMessage(), throwable); + } + } + } + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + return uris; + } + + + /** + * Remove a cookie from store + */ + @Override + public boolean remove(URI uri, HttpCookie cookie) { + if (cookie == null) { + return true; + } + + tryInit(); + + boolean modified = false; + try { + WhereBuilder where = WhereBuilder.b("name", "=", cookie.getName()); + + String domain = cookie.getDomain(); + if (!TextUtils.isEmpty(domain)) { + where.and("domain", "=", domain); + } + + String path = cookie.getPath(); + if (!TextUtils.isEmpty(path)) { + if (path.length() > 1 && path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + where.and("path", "=", path); + } + + db.delete(CookieEntity.class, where); + + modified = true; + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + return modified; + } + + + /** + * Remove all cookies in this cookie store. + */ + @Override + public boolean removeAll() { + tryInit(); + + try { + db.delete(CookieEntity.class); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + return true; + } + + private void trimSize() { + trimExecutor.execute(new Runnable() { + @Override + public void run() { + tryInit(); + + long current = System.currentTimeMillis(); + if (current - lastTrimTime < TRIM_TIME_SPAN) { + return; + } else { + lastTrimTime = current; + } + + // delete expires + try { + db.delete(CookieEntity.class, WhereBuilder + .b("expiry", "<", System.currentTimeMillis()) + .and("expiry", "!=", -1L)); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + // trim by limit count + try { + int count = (int) db.selector(CookieEntity.class).count(); + if (count > LIMIT_COUNT + 10) { + List rmList = db.selector(CookieEntity.class) + .where("expiry", "!=", -1L).orderBy("expiry") + .limit(count - LIMIT_COUNT).findAll(); + if (rmList != null) { + db.delete(rmList); + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + }); + } + + private URI getEffectiveURI(final URI uri) { + URI effectiveURI = null; + try { + effectiveURI = new URI("http", + uri.getHost(), + uri.getPath(), + null, // query component + null // fragment component + ); + } catch (Throwable ex) { + LogUtil.w(ex.getMessage(), ex); + effectiveURI = uri; + } + + return effectiveURI; + } +} diff --git a/app/src/main/java/org/xutils/http/loader/BooleanLoader.java b/app/src/main/java/org/xutils/http/loader/BooleanLoader.java new file mode 100644 index 0000000..1b2729c --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/BooleanLoader.java @@ -0,0 +1,32 @@ +package org.xutils.http.loader; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.http.request.UriRequest; + +/** + * Author: wyouflf + * Time: 2014/05/30 + */ +/*package*/ class BooleanLoader extends Loader { + + @Override + public Loader newInstance() { + return new BooleanLoader(); + } + + @Override + public Boolean load(final UriRequest request) throws Throwable { + request.sendRequest(); + return request.getResponseCode() < 300; + } + + @Override + public Boolean loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + return null; + } + + @Override + public void save2Cache(final UriRequest request) { + + } +} diff --git a/app/src/main/java/org/xutils/http/loader/ByteArrayLoader.java b/app/src/main/java/org/xutils/http/loader/ByteArrayLoader.java new file mode 100644 index 0000000..43253aa --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/ByteArrayLoader.java @@ -0,0 +1,42 @@ +package org.xutils.http.loader; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.common.util.IOUtil; +import org.xutils.http.request.UriRequest; + +/** + * Author: wyouflf + * Time: 2014/05/30 + */ +/*package*/ class ByteArrayLoader extends Loader { + + private byte[] resultData; + + @Override + public Loader newInstance() { + return new ByteArrayLoader(); + } + + @Override + public byte[] load(final UriRequest request) throws Throwable { + request.sendRequest(); + resultData = IOUtil.readBytes(request.getInputStream()); + return resultData; + } + + @Override + public byte[] loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + if (cacheEntity != null) { + byte[] data = cacheEntity.getBytesContent(); + if (data != null && data.length > 0) { + return data; + } + } + return null; + } + + @Override + public void save2Cache(final UriRequest request) { + saveByteArrayCache(request, resultData); + } +} diff --git a/app/src/main/java/org/xutils/http/loader/FileLoader.java b/app/src/main/java/org/xutils/http/loader/FileLoader.java new file mode 100644 index 0000000..80c1e37 --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/FileLoader.java @@ -0,0 +1,351 @@ +package org.xutils.http.loader; + +import android.text.TextUtils; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.cache.DiskCacheFile; +import org.xutils.cache.LruDiskCache; +import org.xutils.common.Callback; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.common.util.ProcessLock; +import org.xutils.ex.FileLockedException; +import org.xutils.ex.HttpException; +import org.xutils.http.RequestParams; +import org.xutils.http.request.UriRequest; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.Date; + +/** + * Author: wyouflf + * Time: 2014/05/30 + * 下载参数策略: + * 1. RequestParams#saveFilePath不为空时, 目标文件保存在saveFilePath; + * 否则由Cache策略分配文件下载路径. + * 2. 下载时临时目标文件路径为tempSaveFilePath, 下载完后进行a: CacheFile#commit; b:重命名等操作. + * 断点下载策略: + * 1. 要下载的目标文件不存在或小于 CHECK_SIZE 时删除目标文件, 重新下载. + * 2. 若文件存在且大于 CHECK_SIZE, range = fileLen - CHECK_SIZE , 校验check_buffer, 相同: 继续下载; + * 不相同: 删掉目标文件, 并抛出RuntimeException(HttpRetryHandler会使下载重新开始). + */ +public class FileLoader extends Loader { + + private static final int CHECK_SIZE = 512; + + private RequestParams params; + private String tempSaveFilePath; + private String saveFilePath; + private boolean isAutoResume; + private boolean isAutoRename; + private long contentLength; + private String responseFileName; + + private DiskCacheFile diskCacheFile; + + @Override + public Loader newInstance() { + return new FileLoader(); + } + + @Override + public void setParams(final RequestParams params) { + if (params != null) { + this.params = params; + isAutoResume = params.isAutoResume(); + isAutoRename = params.isAutoRename(); + } + } + + protected File load(final InputStream in) throws Throwable { + File targetFile = null; + BufferedInputStream bis = null; + BufferedOutputStream bos = null; + try { + targetFile = new File(tempSaveFilePath); + if (targetFile.isDirectory()) { + throw new IOException("could not create the file: " + tempSaveFilePath); + } + if (!targetFile.exists()) { + File dir = targetFile.getParentFile(); + if ((!dir.exists() && !dir.mkdirs()) || !dir.isDirectory()) { + throw new IOException("could not create the dir: " + dir.getAbsolutePath()); + } + } + + // 处理[断点逻辑2](见文件头doc) + long targetFileLen = targetFile.length(); + if (isAutoResume && targetFileLen > 0) { + FileInputStream fis = null; + try { + long filePos = targetFileLen - CHECK_SIZE; + if (filePos > 0) { + fis = new FileInputStream(targetFile); + byte[] fileCheckBuffer = IOUtil.readBytes(fis, filePos, CHECK_SIZE); + byte[] checkBuffer = IOUtil.readBytes(in, 0, CHECK_SIZE); + if (!Arrays.equals(checkBuffer, fileCheckBuffer)) { + IOUtil.closeQuietly(fis); // 先关闭文件流, 否则文件删除会失败. + IOUtil.deleteFileOrDir(targetFile); + throw new RuntimeException("need retry"); + } else { + contentLength -= CHECK_SIZE; + } + } else { + IOUtil.deleteFileOrDir(targetFile); + throw new RuntimeException("need retry"); + } + } finally { + IOUtil.closeQuietly(fis); + } + } + + // 开始下载 + long current = 0; + FileOutputStream fileOutputStream = null; + if (isAutoResume) { + current = targetFileLen; + fileOutputStream = new FileOutputStream(targetFile, true); + } else { + fileOutputStream = new FileOutputStream(targetFile); + } + + long total = contentLength + current; + bis = new BufferedInputStream(in); + bos = new BufferedOutputStream(fileOutputStream); + + if (progressHandler != null && !progressHandler.updateProgress(total, current, true)) { + throw new Callback.CancelledException("download stopped!"); + } + + byte[] tmp = new byte[4096]; + int len; + while ((len = bis.read(tmp)) != -1) { + + // 防止父文件夹被其他进程删除, 继续写入时造成父文件夹变为0字节文件的问题. + if (!targetFile.getParentFile().exists()) { + targetFile.getParentFile().mkdirs(); + throw new IOException("parent be deleted!"); + } + + bos.write(tmp, 0, len); + current += len; + if (progressHandler != null) { + if (!progressHandler.updateProgress(total, current, false)) { + bos.flush(); + throw new Callback.CancelledException("download stopped!"); + } + } + } + bos.flush(); + // 处理[下载逻辑2.a](见文件头doc) + if (diskCacheFile != null) { + targetFile = diskCacheFile.commit(); + } + + if (progressHandler != null) { + progressHandler.updateProgress(total, current, true); + } + } finally { + IOUtil.closeQuietly(bis); + IOUtil.closeQuietly(bos); + } + + return autoRename(targetFile); + } + + @Override + public File load(final UriRequest request) throws Throwable { + ProcessLock processLock = null; + File result = null; + try { + + // 处理[下载逻辑1](见文件头doc) + saveFilePath = params.getSaveFilePath(); + diskCacheFile = null; + if (TextUtils.isEmpty(saveFilePath)) { + + if (progressHandler != null && !progressHandler.updateProgress(0, 0, false)) { + throw new Callback.CancelledException("download stopped!"); + } + + // 保存路径为空, 存入磁盘缓存. + initDiskCacheFile(request); + } else { + tempSaveFilePath = saveFilePath + ".tmp"; + } + + if (progressHandler != null && !progressHandler.updateProgress(0, 0, false)) { + throw new Callback.CancelledException("download stopped!"); + } + + // 等待, 若不能下载则取消此次下载. + processLock = ProcessLock.tryLock(saveFilePath + "_lock", true); + if (processLock == null || !processLock.isValid()) { + throw new FileLockedException("download exists: " + saveFilePath); + } + + params = request.getParams(); + {// 处理[断点逻辑1](见文件头doc) + long range = 0; + if (isAutoResume) { + File tempFile = new File(tempSaveFilePath); + long fileLen = tempFile.length(); + if (fileLen <= CHECK_SIZE) { + IOUtil.deleteFileOrDir(tempFile); + range = 0; + } else { + range = fileLen - CHECK_SIZE; + } + } + // retry 时需要覆盖Range参数 + params.setHeader("Range", "bytes=" + range + "-"); + } + + if (progressHandler != null && !progressHandler.updateProgress(0, 0, false)) { + throw new Callback.CancelledException("download stopped!"); + } + + request.sendRequest(); // may be throw an HttpException + + contentLength = request.getContentLength(); + if (isAutoRename) { + responseFileName = getResponseFileName(request); + } + if (isAutoResume) { + isAutoResume = isSupportRange(request); + } + + if (progressHandler != null && !progressHandler.updateProgress(0, 0, false)) { + throw new Callback.CancelledException("download stopped!"); + } + + if (diskCacheFile != null) { + try { + DiskCacheEntity entity = diskCacheFile.getCacheEntity(); + entity.setLastAccess(System.currentTimeMillis()); + entity.setEtag(request.getETag()); + entity.setExpires(request.getExpiration()); + entity.setLastModify(new Date(request.getLastModified())); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + result = this.load(request.getInputStream()); + } catch (HttpException httpException) { + if (httpException.getCode() == 416) { + if (diskCacheFile != null) { + result = diskCacheFile.commit(); + } else { + result = new File(tempSaveFilePath); + } + // 从缓存获取文件, 不rename和断点, 直接退出. + if (result != null && result.exists()) { + if (isAutoRename) { + responseFileName = getResponseFileName(request); + } + result = autoRename(result); + } else { + IOUtil.deleteFileOrDir(result); + throw new IllegalStateException("cache file not found" + request.getCacheKey()); + } + } else { + throw httpException; + } + } finally { + IOUtil.closeQuietly(processLock); + IOUtil.closeQuietly(diskCacheFile); + } + return result; + } + + // 保存路径为空, 存入磁盘缓存. + private void initDiskCacheFile(final UriRequest request) throws Throwable { + + DiskCacheEntity entity = new DiskCacheEntity(); + entity.setKey(request.getCacheKey()); + diskCacheFile = LruDiskCache.getDiskCache(params.getCacheDirName()).createDiskCacheFile(entity); + + if (diskCacheFile != null) { + saveFilePath = diskCacheFile.getAbsolutePath(); + // diskCacheFile is a temp path, diskCacheFile.commit() return the dest file. + tempSaveFilePath = saveFilePath; + isAutoRename = false; + } else { + throw new IOException("create cache file error:" + request.getCacheKey()); + } + } + + // 处理[下载逻辑2.b](见文件头doc) + private File autoRename(File loadedFile) { + if (isAutoRename && loadedFile.exists() && !TextUtils.isEmpty(responseFileName)) { + File newFile = new File(loadedFile.getParent(), responseFileName); + while (newFile.exists()) { + newFile = new File(loadedFile.getParent(), System.currentTimeMillis() + responseFileName); + } + return loadedFile.renameTo(newFile) ? newFile : loadedFile; + } else if (!saveFilePath.equals(tempSaveFilePath)) { + File newFile = new File(saveFilePath); + return loadedFile.renameTo(newFile) ? newFile : loadedFile; + } else { + return loadedFile; + } + } + + private static String getResponseFileName(UriRequest request) { + if (request == null) return null; + String disposition = request.getResponseHeader("Content-Disposition"); + if (!TextUtils.isEmpty(disposition)) { + int startIndex = disposition.indexOf("filename="); + if (startIndex > 0) { + startIndex += 9; // "filename=".length() + int endIndex = disposition.indexOf(";", startIndex); + if (endIndex < 0) { + endIndex = disposition.length(); + } + if (endIndex > startIndex) { + try { + String name = URLDecoder.decode( + disposition.substring(startIndex, endIndex), + request.getParams().getCharset()); + if (name.startsWith("\"") && name.endsWith("\"")) { + name = name.substring(1, name.length() - 1); + } + return name; + } catch (UnsupportedEncodingException ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } + return null; + } + + private static boolean isSupportRange(UriRequest request) { + if (request == null) return false; + String ranges = request.getResponseHeader("Accept-Ranges"); + if (ranges != null) { + return ranges.contains("bytes"); + } + ranges = request.getResponseHeader("Content-Range"); + return ranges != null && ranges.contains("bytes"); + } + + @Override + public File loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + return LruDiskCache.getDiskCache(params.getCacheDirName()).getDiskCacheFile(cacheEntity.getKey()); + } + + @Override + public void save2Cache(final UriRequest request) { + // the file caches already saved by diskCacheFile#commit + } +} diff --git a/app/src/main/java/org/xutils/http/loader/InputStreamLoader.java b/app/src/main/java/org/xutils/http/loader/InputStreamLoader.java new file mode 100644 index 0000000..b762481 --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/InputStreamLoader.java @@ -0,0 +1,36 @@ +package org.xutils.http.loader; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.http.request.UriRequest; + +import java.io.InputStream; + +/** + * 建议配合 {@link org.xutils.common.Callback.PrepareCallback} 使用, + * 将PrepareType设置为InputStream, 以便在PrepareCallback#prepare中做耗时的数据任务处理. + *

+ * Author: wyouflf + * Time: 2014/05/30 + */ +/*package*/ class InputStreamLoader extends Loader { + + @Override + public Loader newInstance() { + return new InputStreamLoader(); + } + + @Override + public InputStream load(final UriRequest request) throws Throwable { + request.sendRequest(); + return request.getInputStream(); + } + + @Override + public InputStream loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + return null; + } + + @Override + public void save2Cache(final UriRequest request) { + } +} diff --git a/app/src/main/java/org/xutils/http/loader/IntegerLoader.java b/app/src/main/java/org/xutils/http/loader/IntegerLoader.java new file mode 100644 index 0000000..2c97f88 --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/IntegerLoader.java @@ -0,0 +1,31 @@ +package org.xutils.http.loader; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.http.request.UriRequest; + +/** + * Author: wyouflf + * Time: 2014/10/17 + */ +/*package*/ class IntegerLoader extends Loader { + @Override + public Loader newInstance() { + return new IntegerLoader(); + } + + @Override + public Integer load(UriRequest request) throws Throwable { + request.sendRequest(); + return request.getResponseCode(); + } + + @Override + public Integer loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + return null; + } + + @Override + public void save2Cache(UriRequest request) { + + } +} diff --git a/app/src/main/java/org/xutils/http/loader/JSONArrayLoader.java b/app/src/main/java/org/xutils/http/loader/JSONArrayLoader.java new file mode 100644 index 0000000..52d7c3b --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/JSONArrayLoader.java @@ -0,0 +1,58 @@ +package org.xutils.http.loader; + +import android.text.TextUtils; + +import org.json.JSONArray; +import org.xutils.cache.DiskCacheEntity; +import org.xutils.common.util.IOUtil; +import org.xutils.http.RequestParams; +import org.xutils.http.request.UriRequest; + +/** + * Author: wyouflf + * Time: 2014/06/16 + */ +/*package*/ class JSONArrayLoader extends Loader { + + private String charset = "UTF-8"; + private String resultStr = null; + + @Override + public Loader newInstance() { + return new JSONArrayLoader(); + } + + @Override + public void setParams(final RequestParams params) { + if (params != null) { + String charset = params.getCharset(); + if (!TextUtils.isEmpty(charset)) { + this.charset = charset; + } + } + } + + @Override + public JSONArray load(final UriRequest request) throws Throwable { + request.sendRequest(); + resultStr = IOUtil.readStr(request.getInputStream(), charset); + return new JSONArray(resultStr); + } + + @Override + public JSONArray loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + if (cacheEntity != null) { + String text = cacheEntity.getTextContent(); + if (!TextUtils.isEmpty(text)) { + return new JSONArray(text); + } + } + + return null; + } + + @Override + public void save2Cache(UriRequest request) { + saveStringCache(request, resultStr); + } +} diff --git a/app/src/main/java/org/xutils/http/loader/JSONObjectLoader.java b/app/src/main/java/org/xutils/http/loader/JSONObjectLoader.java new file mode 100644 index 0000000..02ee0c7 --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/JSONObjectLoader.java @@ -0,0 +1,58 @@ +package org.xutils.http.loader; + +import android.text.TextUtils; + +import org.json.JSONObject; +import org.xutils.cache.DiskCacheEntity; +import org.xutils.common.util.IOUtil; +import org.xutils.http.RequestParams; +import org.xutils.http.request.UriRequest; + +/** + * Author: wyouflf + * Time: 2014/06/16 + */ +/*package*/ class JSONObjectLoader extends Loader { + + private String charset = "UTF-8"; + private String resultStr = null; + + @Override + public Loader newInstance() { + return new JSONObjectLoader(); + } + + @Override + public void setParams(final RequestParams params) { + if (params != null) { + String charset = params.getCharset(); + if (!TextUtils.isEmpty(charset)) { + this.charset = charset; + } + } + } + + @Override + public JSONObject load(final UriRequest request) throws Throwable { + request.sendRequest(); + resultStr = IOUtil.readStr(request.getInputStream(), charset); + return new JSONObject(resultStr); + } + + @Override + public JSONObject loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + if (cacheEntity != null) { + String text = cacheEntity.getTextContent(); + if (!TextUtils.isEmpty(text)) { + return new JSONObject(text); + } + } + + return null; + } + + @Override + public void save2Cache(UriRequest request) { + saveStringCache(request, resultStr); + } +} diff --git a/app/src/main/java/org/xutils/http/loader/Loader.java b/app/src/main/java/org/xutils/http/loader/Loader.java new file mode 100644 index 0000000..b76fc39 --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/Loader.java @@ -0,0 +1,58 @@ +package org.xutils.http.loader; + + +import android.text.TextUtils; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.cache.LruDiskCache; +import org.xutils.http.ProgressHandler; +import org.xutils.http.RequestParams; +import org.xutils.http.request.UriRequest; + +import java.util.Date; + +/** + * Author: wyouflf + * Time: 2014/05/26 + */ +public abstract class Loader { + + protected ProgressHandler progressHandler; + + public void setParams(final RequestParams params) { + } + + public void setProgressHandler(final ProgressHandler callbackHandler) { + this.progressHandler = callbackHandler; + } + + protected void saveStringCache(UriRequest request, String resultStr) { + saveCacheInternal(request, resultStr, null); + } + + protected void saveByteArrayCache(UriRequest request, byte[] resultData) { + saveCacheInternal(request, null, resultData); + } + + public abstract Loader newInstance(); + + public abstract T load(final UriRequest request) throws Throwable; + + public abstract T loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable; + + public abstract void save2Cache(final UriRequest request); + + private void saveCacheInternal(UriRequest request, String resultStr, byte[] resultData) { + if (!TextUtils.isEmpty(resultStr) || (resultData != null && resultData.length > 0)) { + DiskCacheEntity entity = new DiskCacheEntity(); + entity.setKey(request.getCacheKey()); + entity.setLastAccess(System.currentTimeMillis()); + entity.setEtag(request.getETag()); + entity.setExpires(request.getExpiration()); + entity.setLastModify(new Date(request.getLastModified())); + entity.setTextContent(resultStr); + entity.setBytesContent(resultData); + LruDiskCache.getDiskCache(request.getParams().getCacheDirName()).put(entity); + } + } +} diff --git a/app/src/main/java/org/xutils/http/loader/LoaderFactory.java b/app/src/main/java/org/xutils/http/loader/LoaderFactory.java new file mode 100644 index 0000000..578de26 --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/LoaderFactory.java @@ -0,0 +1,56 @@ +package org.xutils.http.loader; + + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.util.HashMap; + +/** + * Author: wyouflf + * Time: 2014/05/26 + */ +public final class LoaderFactory { + + private LoaderFactory() { + } + + /** + * key: loadType + */ + private static final HashMap converterHashMap = new HashMap(); + + static { + converterHashMap.put(JSONObject.class, new JSONObjectLoader()); + converterHashMap.put(JSONArray.class, new JSONArrayLoader()); + converterHashMap.put(String.class, new StringLoader()); + converterHashMap.put(File.class, new FileLoader()); + converterHashMap.put(byte[].class, new ByteArrayLoader()); + converterHashMap.put(InputStream.class, new InputStreamLoader()); + + BooleanLoader booleanLoader = new BooleanLoader(); + converterHashMap.put(boolean.class, booleanLoader); + converterHashMap.put(Boolean.class, booleanLoader); + + IntegerLoader integerLoader = new IntegerLoader(); + converterHashMap.put(int.class, integerLoader); + converterHashMap.put(Integer.class, integerLoader); + } + + public static Loader getLoader(Type type) { + Loader result = converterHashMap.get(type); + if (result == null) { + result = new ObjectLoader(type); + } else { + result = result.newInstance(); + } + return result; + } + + public static void registerLoader(Type type, Loader loader) { + converterHashMap.put(type, loader); + } +} diff --git a/app/src/main/java/org/xutils/http/loader/ObjectLoader.java b/app/src/main/java/org/xutils/http/loader/ObjectLoader.java new file mode 100644 index 0000000..046a104 --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/ObjectLoader.java @@ -0,0 +1,105 @@ +package org.xutils.http.loader; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.common.util.ParameterizedTypeUtil; +import org.xutils.http.RequestParams; +import org.xutils.http.annotation.HttpResponse; +import org.xutils.http.app.ResponseParser; +import org.xutils.http.request.UriRequest; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.List; + +/** + * Created by lei.jiao on 2014/6/27. + * 其他对象的下载转换. + * 使用类型上的@HttpResponse注解信息进行数据转换. + */ +/*package*/ class ObjectLoader extends Loader { + + private final Type objectType; + private final Class objectClass; + private final ResponseParser parser; + private final Loader innerLoader; + + public ObjectLoader(Type objectType) { + this.objectType = objectType; + + // check loadType & resultType + if (objectType instanceof ParameterizedType) { + objectClass = (Class) ((ParameterizedType) objectType).getRawType(); + } else if (objectType instanceof TypeVariable) { + throw new IllegalArgumentException( + "not support callback type " + objectType.toString()); + } else { + objectClass = (Class) objectType; + } + + HttpResponse response = null; + Type itemType = objectType; + if (List.class.equals(objectClass)) { + itemType = ParameterizedTypeUtil.getParameterizedType(this.objectType, List.class, 0); + Class itemClass = null; + if (itemType instanceof ParameterizedType) { + itemClass = (Class) ((ParameterizedType) itemType).getRawType(); + } else if (itemType instanceof TypeVariable) { + throw new IllegalArgumentException( + "not support callback type " + itemType.toString()); + } else { + itemClass = (Class) itemType; + } + + response = itemClass.getAnnotation(HttpResponse.class); + } else { + response = objectClass.getAnnotation(HttpResponse.class); + } + if (response != null) { + try { + Class parserCls = response.parser(); + this.parser = parserCls.newInstance(); + this.innerLoader = LoaderFactory.getLoader( + ParameterizedTypeUtil.getParameterizedType(parserCls, ResponseParser.class, 0)); + } catch (Throwable ex) { + throw new RuntimeException("create parser error", ex); + } + } else { + throw new IllegalArgumentException("not found @HttpResponse from " + itemType); + } + + if (innerLoader instanceof ObjectLoader) { + throw new IllegalArgumentException("not support callback type " + itemType); + } + } + + @Override + public Loader newInstance() { + throw new IllegalAccessError("use constructor create ObjectLoader."); + } + + @Override + public void setParams(final RequestParams params) { + this.innerLoader.setParams(params); + } + + @Override + @SuppressWarnings("unchecked") + public Object load(final UriRequest request) throws Throwable { + request.setResponseParser(parser); + Object innerLoaderResult = innerLoader.load(request); + return parser.parse(objectType, objectClass, innerLoaderResult); + } + + @Override + @SuppressWarnings("unchecked") + public Object loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + Object innerLoaderResult = innerLoader.loadFromCache(cacheEntity); + return parser.parse(objectType, objectClass, innerLoaderResult); + } + + @Override + public void save2Cache(UriRequest request) { + innerLoader.save2Cache(request); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/xutils/http/loader/StringLoader.java b/app/src/main/java/org/xutils/http/loader/StringLoader.java new file mode 100644 index 0000000..a6a237d --- /dev/null +++ b/app/src/main/java/org/xutils/http/loader/StringLoader.java @@ -0,0 +1,54 @@ +package org.xutils.http.loader; + +import android.text.TextUtils; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.common.util.IOUtil; +import org.xutils.http.RequestParams; +import org.xutils.http.request.UriRequest; + +/** + * Author: wyouflf + * Time: 2014/05/30 + */ +/*package*/ class StringLoader extends Loader { + + private String charset = "UTF-8"; + private String resultStr = null; + + @Override + public Loader newInstance() { + return new StringLoader(); + } + + @Override + public void setParams(final RequestParams params) { + if (params != null) { + String charset = params.getCharset(); + if (!TextUtils.isEmpty(charset)) { + this.charset = charset; + } + } + } + + @Override + public String load(final UriRequest request) throws Throwable { + request.sendRequest(); + resultStr = IOUtil.readStr(request.getInputStream(), charset); + return resultStr; + } + + @Override + public String loadFromCache(final DiskCacheEntity cacheEntity) throws Throwable { + if (cacheEntity != null) { + return cacheEntity.getTextContent(); + } + + return null; + } + + @Override + public void save2Cache(UriRequest request) { + saveStringCache(request, resultStr); + } +} diff --git a/app/src/main/java/org/xutils/http/request/AssetsRequest.java b/app/src/main/java/org/xutils/http/request/AssetsRequest.java new file mode 100644 index 0000000..545f765 --- /dev/null +++ b/app/src/main/java/org/xutils/http/request/AssetsRequest.java @@ -0,0 +1,31 @@ +package org.xutils.http.request; + +import android.content.Context; + +import org.xutils.http.RequestParams; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; + +/** + * Created by wyouflf on 15/11/4. + * Assets资源文件请求 + */ +public class AssetsRequest extends ResRequest { + + public AssetsRequest(RequestParams params, Type loadType) throws Throwable { + super(params, loadType); + } + + @Override + public InputStream getInputStream() throws IOException { + if (inputStream == null) { + Context context = params.getContext(); + String assetsPath = queryUrl.replace("assets://", ""); + inputStream = context.getResources().getAssets().open(assetsPath); + contentLength = inputStream.available(); + } + return inputStream; + } +} diff --git a/app/src/main/java/org/xutils/http/request/HttpRequest.java b/app/src/main/java/org/xutils/http/request/HttpRequest.java new file mode 100644 index 0000000..a47adbf --- /dev/null +++ b/app/src/main/java/org/xutils/http/request/HttpRequest.java @@ -0,0 +1,466 @@ +package org.xutils.http.request; + +import android.annotation.TargetApi; +import android.os.Build; +import android.text.TextUtils; +import org.xutils.cache.DiskCacheEntity; +import org.xutils.cache.LruDiskCache; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.KeyValue; +import org.xutils.common.util.LogUtil; +import org.xutils.ex.HttpException; +import org.xutils.http.HttpMethod; +import org.xutils.http.RequestParams; +import org.xutils.http.body.ProgressBody; +import org.xutils.http.body.RequestBody; +import org.xutils.http.cookie.DbCookieStore; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.net.*; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * Created by wyouflf on 15/7/23. + * Uri请求发送和数据接收 + */ +public class HttpRequest extends UriRequest { + + private String cacheKey = null; + private boolean isLoading = false; + private InputStream inputStream = null; + private HttpURLConnection connection = null; + private int responseCode = 0; + + // cookie manager + private static final CookieManager COOKIE_MANAGER = + new CookieManager(DbCookieStore.INSTANCE, CookiePolicy.ACCEPT_ALL); + + public HttpRequest(RequestParams params, Type loadType) throws Throwable { + super(params, loadType); + } + + // build query + @Override + protected String buildQueryUrl(RequestParams params) throws IOException { + String uri = params.getUri(); + StringBuilder queryBuilder = new StringBuilder(uri); + List queryParams = params.getQueryStringParams(); + + if (queryParams != null && !queryParams.isEmpty()) { + if (!uri.contains("?")) { + queryBuilder.append("?"); + } else if (!uri.endsWith("?")) { + queryBuilder.append("&"); + } + + for (KeyValue kv : queryParams) { + String name = kv.key; + String value = kv.getValueStrOrNull(); + if (!TextUtils.isEmpty(name) && value != null) { + queryBuilder.append(URLEncoder.encode(name, params.getCharset()).replaceAll("\\+", "%20")) + .append("=") + .append(URLEncoder.encode(value, params.getCharset()).replaceAll("\\+", "%20")) + .append("&"); + } + } + + if (queryBuilder.charAt(queryBuilder.length() - 1) == '&') { + queryBuilder.deleteCharAt(queryBuilder.length() - 1); + } + + if (queryBuilder.charAt(queryBuilder.length() - 1) == '?') { + queryBuilder.deleteCharAt(queryBuilder.length() - 1); + } + } + + return queryBuilder.toString(); + } + + @Override + public String getRequestUri() { + String result = queryUrl; + if (connection != null) { + URL url = connection.getURL(); + if (url != null) { + result = url.toString(); + } + } + return result; + } + + /** + * invoke via Loader + */ + @Override + @TargetApi(Build.VERSION_CODES.KITKAT) + public void sendRequest() throws Throwable { + isLoading = false; + responseCode = 0; + + URL url = new URL(queryUrl); + { // init connection + Proxy proxy = params.getProxy(); + if (proxy != null) { + connection = (HttpURLConnection) url.openConnection(proxy); + } else { + connection = (HttpURLConnection) url.openConnection(); + } + + // try to fix bug: accidental EOFException before API 19 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + connection.setRequestProperty("Connection", "close"); + } + + connection.setReadTimeout(params.getReadTimeout()); + connection.setConnectTimeout(params.getConnectTimeout()); + connection.setInstanceFollowRedirects(params.getRedirectHandler() == null); + if (connection instanceof HttpsURLConnection) { + SSLSocketFactory sslSocketFactory = params.getSslSocketFactory(); + if (sslSocketFactory != null) { + ((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory); + } + + HostnameVerifier hostnameVerifier = params.getHostnameVerifier(); + if (hostnameVerifier != null) { + ((HttpsURLConnection) connection).setHostnameVerifier(hostnameVerifier); + } + } + } + + if (params.isUseCookie()) {// add cookies + try { + Map> singleMap = + COOKIE_MANAGER.get(url.toURI(), new HashMap>(0)); + List cookies = singleMap.get("Cookie"); + if (cookies != null) { + connection.setRequestProperty("Cookie", TextUtils.join(";", cookies)); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + {// add headers + List headers = params.getHeaders(); + if (headers != null) { + for (RequestParams.Header header : headers) { + String name = header.key; + String value = header.getValueStrOrNull(); + if (!TextUtils.isEmpty(name)) { + if (header.setHeader) { + connection.setRequestProperty(name, value); + } else { + connection.addRequestProperty(name, value); + } + } + } + } + } + + // intercept response + if (responseParser != null) { + responseParser.beforeRequest(this); + } + if (requestInterceptListener != null) { + requestInterceptListener.beforeRequest(this); + } + + { // write body + HttpMethod method = params.getMethod(); + try { + connection.setRequestMethod(method.toString()); + } catch (ProtocolException ex) { + try { // fix: HttpURLConnection not support PATCH method. + Field methodField = HttpURLConnection.class.getDeclaredField("method"); + methodField.setAccessible(true); + methodField.set(connection, method.toString()); + } catch (Throwable ignored) { + throw ex; + } + } + if (HttpMethod.permitsRequestBody(method)) { + RequestBody body = params.getRequestBody(); + if (body != null) { + if (body instanceof ProgressBody) { + ((ProgressBody) body).setProgressHandler(progressHandler); + } + String contentType = body.getContentType(); + if (!TextUtils.isEmpty(contentType)) { + connection.setRequestProperty("Content-Type", contentType); + } + boolean isChunkedMode = false; + long contentLength = body.getContentLength(); + if (contentLength < 0) { + connection.setChunkedStreamingMode(256 * 1024); + isChunkedMode = true; + } else { + if (contentLength < Integer.MAX_VALUE) { + connection.setFixedLengthStreamingMode((int) contentLength); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + connection.setFixedLengthStreamingMode(contentLength); + } else { + connection.setChunkedStreamingMode(256 * 1024); + isChunkedMode = true; + } + } + + if (isChunkedMode) { + connection.setRequestProperty("Transfer-Encoding", "chunked"); + } else { + connection.setRequestProperty("Content-Length", String.valueOf(contentLength)); + } + + connection.setDoOutput(true); + body.writeTo(connection.getOutputStream()); + } + } + } + + if (params.isUseCookie()) { // save cookies + try { + Map> headers = connection.getHeaderFields(); + if (headers != null) { + COOKIE_MANAGER.put(url.toURI(), headers); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + // check response code + responseCode = connection.getResponseCode(); + { // intercept response + if (responseParser != null) { + responseParser.afterRequest(this); + } + if (requestInterceptListener != null) { + requestInterceptListener.afterRequest(this); + } + } + if (responseCode == 204 || responseCode == 205) { // empty content + throw new HttpException(responseCode, this.getResponseMessage()); + } else if (responseCode >= 300) { + HttpException httpException = new HttpException(responseCode, this.getResponseMessage()); + try { + httpException.setResult(IOUtil.readStr(this.getInputStream(), params.getCharset())); + } catch (Throwable ex) { + LogUtil.w(ex.getMessage(), ex); + } + LogUtil.e(httpException.toString() + ", url: " + queryUrl); + throw httpException; + } + + isLoading = true; + } + + @Override + public boolean isLoading() { + return isLoading; + } + + @Override + public String getCacheKey() { + if (cacheKey == null) { + + cacheKey = params.getCacheKey(); + + if (TextUtils.isEmpty(cacheKey)) { + cacheKey = params.toString(); + } + } + return cacheKey; + } + + @Override + public Object loadResult() throws Throwable { + isLoading = true; + return super.loadResult(); + } + + /** + * 尝试从缓存获取结果, 并为请求头加入缓存控制参数. + */ + @Override + public Object loadResultFromCache() throws Throwable { + isLoading = true; + DiskCacheEntity cacheEntity = LruDiskCache.getDiskCache(params.getCacheDirName()) + .setMaxSize(params.getCacheSize()) + .get(this.getCacheKey()); + + if (cacheEntity != null) { + if (HttpMethod.permitsCache(params.getMethod())) { + Date lastModified = cacheEntity.getLastModify(); + if (lastModified.getTime() > 0) { + params.setHeader("If-Modified-Since", toGMTString(lastModified)); + } + String eTag = cacheEntity.getEtag(); + if (!TextUtils.isEmpty(eTag)) { + params.setHeader("If-None-Match", eTag); + } + } + return loader.loadFromCache(cacheEntity); + } else { + return null; + } + } + + @Override + public void clearCacheHeader() { + params.setHeader("If-Modified-Since", null); + params.setHeader("If-None-Match", null); + } + + @Override + public InputStream getInputStream() throws IOException { + if (connection != null && inputStream == null) { + inputStream = connection.getResponseCode() >= 400 ? + connection.getErrorStream() : connection.getInputStream(); + } + return inputStream; + } + + @Override + public void close() throws IOException { + if (inputStream != null) { + IOUtil.closeQuietly(inputStream); + inputStream = null; + } + if (connection != null) { + connection.disconnect(); + //connection = null; + } + } + + @Override + public long getContentLength() { + long result = -1; + if (connection != null) { + try { + String value = connection.getHeaderField("content-length"); + if (value != null) { + result = Long.parseLong(value); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + if (result < 1) { + try { + result = this.getInputStream().available(); + } catch (Throwable ignored) { + } + } + return result; + } + + @Override + public int getResponseCode() throws IOException { + if (connection != null) { + return responseCode; + } else { + if (this.getInputStream() != null) { + return 200; + } else { + return 404; + } + } + } + + @Override + public String getResponseMessage() throws IOException { + if (connection != null) { + return URLDecoder.decode(connection.getResponseMessage(), params.getCharset()); + } else { + return null; + } + } + + @Override + public long getExpiration() { + if (connection == null) return -1L; + + long expiration = -1L; + + // from max-age + String cacheControl = connection.getHeaderField("Cache-Control"); + if (!TextUtils.isEmpty(cacheControl)) { + StringTokenizer tok = new StringTokenizer(cacheControl, ","); + while (tok.hasMoreTokens()) { + String token = tok.nextToken().trim().toLowerCase(); + if (token.startsWith("max-age")) { + int eqIdx = token.indexOf('='); + if (eqIdx > 0) { + try { + String value = token.substring(eqIdx + 1).trim(); + long seconds = Long.parseLong(value); + if (seconds > 0L) { + expiration = System.currentTimeMillis() + seconds * 1000L; + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + break; + } + } + } + + // from expires + if (expiration <= 0L) { + expiration = connection.getExpiration(); + } + + if (expiration <= 0L && params.getCacheMaxAge() > 0L) { + expiration = System.currentTimeMillis() + params.getCacheMaxAge(); + } + + if (expiration <= 0L) { + expiration = Long.MAX_VALUE; + } + return expiration; + } + + @Override + public long getLastModified() { + return getHeaderFieldDate("Last-Modified", System.currentTimeMillis()); + } + + @Override + public String getETag() { + if (connection == null) return null; + return connection.getHeaderField("ETag"); + } + + @Override + public String getResponseHeader(String name) { + if (connection == null) return null; + return connection.getHeaderField(name); + } + + @Override + public Map> getResponseHeaders() { + if (connection == null) return null; + return connection.getHeaderFields(); + } + + @Override + public long getHeaderFieldDate(String name, long defaultValue) { + if (connection == null) return defaultValue; + return connection.getHeaderFieldDate(name, defaultValue); + } + + private static String toGMTString(Date date) { + SimpleDateFormat sdf = new SimpleDateFormat( + "EEE, dd MMM y HH:mm:ss 'GMT'", Locale.US); + TimeZone gmtZone = TimeZone.getTimeZone("GMT"); + sdf.setTimeZone(gmtZone); + return sdf.format(date); + } +} diff --git a/app/src/main/java/org/xutils/http/request/LocalFileRequest.java b/app/src/main/java/org/xutils/http/request/LocalFileRequest.java new file mode 100644 index 0000000..98e09a2 --- /dev/null +++ b/app/src/main/java/org/xutils/http/request/LocalFileRequest.java @@ -0,0 +1,134 @@ +package org.xutils.http.request; + +import org.xutils.common.util.IOUtil; +import org.xutils.http.RequestParams; +import org.xutils.http.loader.FileLoader; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +/** + * Created by wyouflf on 15/11/4. + * 本地文件请求 + */ +public class LocalFileRequest extends UriRequest { + + private InputStream inputStream; + + public LocalFileRequest(RequestParams params, Type loadType) throws Throwable { + super(params, loadType); + } + + @Override + public void sendRequest() throws Throwable { + + } + + @Override + public boolean isLoading() { + return true; + } + + @Override + public String getCacheKey() { + return queryUrl; + } + + @Override + public Object loadResult() throws Throwable { + if (loader instanceof FileLoader) { + return getFile(); + } + return this.loader.load(this); + } + + @Override + public Object loadResultFromCache() throws Throwable { + return null; + } + + @Override + public void clearCacheHeader() { + + } + + @Override + public void save2Cache() { + + } + + private File getFile() { + String filePath = null; + if (queryUrl.startsWith("file:")) { + filePath = queryUrl.substring("file:".length()); + } else { + filePath = queryUrl; + } + // filePath开始位置多余的"/"或被自动去掉 + return new File(filePath); + } + + @Override + public InputStream getInputStream() throws IOException { + if (inputStream == null) { + inputStream = new FileInputStream(getFile()); + } + return inputStream; + } + + @Override + public void close() throws IOException { + IOUtil.closeQuietly(inputStream); + inputStream = null; + } + + @Override + public long getContentLength() { + return getFile().length(); + } + + @Override + public int getResponseCode() throws IOException { + return getFile().exists() ? 200 : 404; + } + + @Override + public String getResponseMessage() throws IOException { + return null; + } + + @Override + public long getExpiration() { + return -1; + } + + @Override + public long getLastModified() { + return getFile().lastModified(); + } + + @Override + public String getETag() { + return null; + } + + @Override + public String getResponseHeader(String name) { + return null; + } + + @Override + public Map> getResponseHeaders() { + return null; + } + + @Override + public long getHeaderFieldDate(String name, long defaultValue) { + return defaultValue; + } +} diff --git a/app/src/main/java/org/xutils/http/request/ResRequest.java b/app/src/main/java/org/xutils/http/request/ResRequest.java new file mode 100644 index 0000000..9dd4a65 --- /dev/null +++ b/app/src/main/java/org/xutils/http/request/ResRequest.java @@ -0,0 +1,175 @@ +package org.xutils.http.request; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.text.TextUtils; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.cache.LruDiskCache; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.http.RequestParams; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * Created by wyouflf on 15/11/4. + * 本地资源请求 + */ +public class ResRequest extends UriRequest { + + private static long lastModifiedTime = 0; + protected long contentLength = 0; + protected InputStream inputStream; + + public ResRequest(RequestParams params, Type loadType) throws Throwable { + super(params, loadType); + } + + @Override + public void sendRequest() throws Throwable { + + } + + @Override + public boolean isLoading() { + return true; + } + + @Override + public String getCacheKey() { + return queryUrl; + } + + @Override + public Object loadResult() throws Throwable { + return this.loader.load(this); + } + + @Override + public Object loadResultFromCache() throws Throwable { + DiskCacheEntity cacheEntity = LruDiskCache.getDiskCache(params.getCacheDirName()) + .setMaxSize(params.getCacheSize()) + .get(this.getCacheKey()); + + if (cacheEntity != null) { + Date lastModifiedDate = cacheEntity.getLastModify(); + if (lastModifiedDate == null || lastModifiedDate.getTime() < getLastModified()) { + return null; + } + return loader.loadFromCache(cacheEntity); + } else { + return null; + } + } + + @Override + public void clearCacheHeader() { + + } + + private int getResId() { + int resId = 0; + String resIdStr = queryUrl.substring("res:".length()); + resIdStr = resIdStr.replace("/", ""); + if (TextUtils.isDigitsOnly(resIdStr)) { + resId = Integer.parseInt(resIdStr); + } + + if (resId <= 0) { + throw new IllegalArgumentException("resId not found in url:" + queryUrl); + } + + return resId; + } + + @Override + public InputStream getInputStream() throws IOException { + if (inputStream == null) { + Context context = params.getContext(); + inputStream = context.getResources().openRawResource(getResId()); + contentLength = inputStream.available(); + } + return inputStream; + } + + @Override + public void close() throws IOException { + IOUtil.closeQuietly(inputStream); + inputStream = null; + } + + @Override + public long getContentLength() { + try { + getInputStream(); + return contentLength; + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + return -1; + } + + @Override + public int getResponseCode() throws IOException { + return getInputStream() != null ? 200 : 404; + } + + @Override + public String getResponseMessage() throws IOException { + return null; + } + + @Override + public long getExpiration() { + return Long.MAX_VALUE; + } + + @Override + public long getLastModified() { + if (lastModifiedTime == 0) { + try { + Context context = params.getContext(); + ApplicationInfo appInfo = context.getApplicationInfo(); + File appFile = new File(appInfo.sourceDir); + if (appFile.exists()) { + lastModifiedTime = appFile.lastModified(); + } + } catch (Throwable ex) { + LogUtil.w(ex.getMessage(), ex); + lastModifiedTime = 0; + } finally { + if (lastModifiedTime == 0) { + lastModifiedTime = System.currentTimeMillis(); + } + } + } + return lastModifiedTime; + } + + @Override + public String getETag() { + return null; + } + + @Override + public String getResponseHeader(String name) { + return null; + } + + @Override + public Map> getResponseHeaders() { + return null; + } + + @Override + public long getHeaderFieldDate(String name, long defaultValue) { + return defaultValue; + } +} diff --git a/app/src/main/java/org/xutils/http/request/UriRequest.java b/app/src/main/java/org/xutils/http/request/UriRequest.java new file mode 100644 index 0000000..00ae40b --- /dev/null +++ b/app/src/main/java/org/xutils/http/request/UriRequest.java @@ -0,0 +1,129 @@ +package org.xutils.http.request; + +import org.xutils.common.util.LogUtil; +import org.xutils.http.ProgressHandler; +import org.xutils.http.RequestParams; +import org.xutils.http.app.RequestInterceptListener; +import org.xutils.http.app.ResponseParser; +import org.xutils.http.loader.Loader; +import org.xutils.http.loader.LoaderFactory; +import org.xutils.x; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +/** + * Created by wyouflf on 15/7/23. + * Uri请求发送和数据接收 + */ +public abstract class UriRequest implements Closeable { + + protected final String queryUrl; + protected final RequestParams params; + protected final Loader loader; + + protected ProgressHandler progressHandler = null; + protected ResponseParser responseParser = null; + protected RequestInterceptListener requestInterceptListener = null; + + public UriRequest(RequestParams params, Type loadType) throws Throwable { + this.params = params; + this.queryUrl = buildQueryUrl(params); + this.loader = LoaderFactory.getLoader(loadType); + this.loader.setParams(params); + } + + // build query + protected String buildQueryUrl(RequestParams params) throws IOException { + return params.getUri(); + } + + public void setProgressHandler(ProgressHandler progressHandler) { + this.progressHandler = progressHandler; + this.loader.setProgressHandler(progressHandler); + } + + public void setResponseParser(ResponseParser responseParser) { + this.responseParser = responseParser; + } + + public void setRequestInterceptListener(RequestInterceptListener requestInterceptListener) { + this.requestInterceptListener = requestInterceptListener; + } + + public RequestParams getParams() { + return params; + } + + public String getRequestUri() { + return queryUrl; + } + + /** + * invoke via Loader + */ + public abstract void sendRequest() throws Throwable; + + public abstract boolean isLoading(); + + public abstract String getCacheKey(); + + /** + * 由loader发起请求, 拿到结果. + */ + public Object loadResult() throws Throwable { + return this.loader.load(this); + } + + /** + * 尝试从缓存获取结果, 并为请求头加入缓存控制参数. + */ + public abstract Object loadResultFromCache() throws Throwable; + + public abstract void clearCacheHeader(); + + public void save2Cache() { + x.task().run(new Runnable() { + @Override + public void run() { + try { + loader.save2Cache(UriRequest.this); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + }); + } + + public abstract InputStream getInputStream() throws IOException; + + @Override + public abstract void close() throws IOException; + + public abstract long getContentLength(); + + public abstract int getResponseCode() throws IOException; + + public abstract String getResponseMessage() throws IOException; + + public abstract long getExpiration(); + + public abstract long getLastModified(); + + public abstract String getETag(); + + public abstract String getResponseHeader(String name); + + public abstract Map> getResponseHeaders(); + + public abstract long getHeaderFieldDate(String name, long defaultValue); + + @Override + public String toString() { + return getRequestUri(); + } +} diff --git a/app/src/main/java/org/xutils/http/request/UriRequestFactory.java b/app/src/main/java/org/xutils/http/request/UriRequestFactory.java new file mode 100644 index 0000000..3ac2c57 --- /dev/null +++ b/app/src/main/java/org/xutils/http/request/UriRequestFactory.java @@ -0,0 +1,81 @@ +package org.xutils.http.request; + +import android.text.TextUtils; + +import org.xutils.common.util.LogUtil; +import org.xutils.http.RequestParams; +import org.xutils.http.app.RequestTracker; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Type; +import java.util.HashMap; + +/** + * Created by wyouflf on 15/11/4. + * Uri请求创建工厂 + */ +public final class UriRequestFactory { + + private static Class defaultTrackerCls; + + private static final HashMap> + SCHEME_CLS_MAP = new HashMap>(); + + private UriRequestFactory() { + } + + public static UriRequest getUriRequest(RequestParams params, Type loadType) throws Throwable { + + // get scheme + String scheme = null; + String uri = params.getUri(); + int index = uri.indexOf(":"); + if (uri.startsWith("/")) { + scheme = "file"; + } else if (index > 0) { + scheme = uri.substring(0, index); + } + + // get UriRequest + if (!TextUtils.isEmpty(scheme)) { + scheme = scheme.toLowerCase(); + Class cls = SCHEME_CLS_MAP.get(scheme); + if (cls != null) { + Constructor constructor + = cls.getConstructor(RequestParams.class, Type.class); + return constructor.newInstance(params, loadType); + } else { + if (scheme.startsWith("http")) { + return new HttpRequest(params, loadType); + } else if (scheme.equals("assets")) { + return new AssetsRequest(params, loadType); + } else if (scheme.equals("file")) { + return new LocalFileRequest(params, loadType); + } else if (scheme.equals("res")) { + return new ResRequest(params, loadType); + } else { + throw new IllegalArgumentException("The url not be support: " + uri); + } + } + } else { + throw new IllegalArgumentException("The url not be support: " + uri); + } + } + + public static void registerDefaultTrackerClass(Class trackerCls) { + UriRequestFactory.defaultTrackerCls = trackerCls; + } + + public static RequestTracker getDefaultTracker() { + try { + return defaultTrackerCls == null ? null : defaultTrackerCls.newInstance(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + return null; + } + + public static void registerRequestClass(String scheme, Class uriRequestCls) { + SCHEME_CLS_MAP.put(scheme, uriRequestCls); + } +} diff --git a/app/src/main/java/org/xutils/image/AsyncDrawable.java b/app/src/main/java/org/xutils/image/AsyncDrawable.java new file mode 100644 index 0000000..d037aad --- /dev/null +++ b/app/src/main/java/org/xutils/image/AsyncDrawable.java @@ -0,0 +1,221 @@ +package org.xutils.image; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.Region; +import android.graphics.drawable.Drawable; + +import java.lang.ref.WeakReference; + +/** + * Author: wyouflf + * Date: 13-11-17 + * Time: 上午11:42 + */ +public final class AsyncDrawable extends Drawable { + + private final WeakReference imageLoaderReference; + + private Drawable baseDrawable; + + public AsyncDrawable(ImageLoader imageLoader, Drawable drawable) { + if (imageLoader == null) { + throw new IllegalArgumentException("imageLoader may not be null"); + } + baseDrawable = drawable; + while (baseDrawable instanceof AsyncDrawable) { + baseDrawable = ((AsyncDrawable) baseDrawable).baseDrawable; + } + imageLoaderReference = new WeakReference(imageLoader); + } + + public ImageLoader getImageLoader() { + return imageLoaderReference.get(); + } + + public void setBaseDrawable(Drawable baseDrawable) { + this.baseDrawable = baseDrawable; + } + + public Drawable getBaseDrawable() { + return baseDrawable; + } + + @Override + public void draw(Canvas canvas) { + if (baseDrawable != null) { + baseDrawable.draw(canvas); + } + } + + @Override + public void setAlpha(int i) { + if (baseDrawable != null) { + baseDrawable.setAlpha(i); + } + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + if (baseDrawable != null) { + baseDrawable.setColorFilter(colorFilter); + } + } + + @Override + public int getOpacity() { + return baseDrawable == null ? PixelFormat.TRANSLUCENT : baseDrawable.getOpacity(); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + if (baseDrawable != null) { + baseDrawable.setBounds(left, top, right, bottom); + } + } + + @Override + public void setBounds(Rect bounds) { + if (baseDrawable != null) { + baseDrawable.setBounds(bounds); + } + } + + @Override + public void setChangingConfigurations(int configs) { + if (baseDrawable != null) { + baseDrawable.setChangingConfigurations(configs); + } + } + + @Override + public int getChangingConfigurations() { + return baseDrawable == null ? 0 : baseDrawable.getChangingConfigurations(); + } + + @Override + public void setDither(boolean dither) { + if (baseDrawable != null) { + baseDrawable.setDither(dither); + } + } + + @Override + public void setFilterBitmap(boolean filter) { + if (baseDrawable != null) { + baseDrawable.setFilterBitmap(filter); + } + } + + @Override + public void invalidateSelf() { + if (baseDrawable != null) { + baseDrawable.invalidateSelf(); + } + } + + @Override + public void scheduleSelf(Runnable what, long when) { + if (baseDrawable != null) { + baseDrawable.scheduleSelf(what, when); + } + } + + @Override + public void unscheduleSelf(Runnable what) { + if (baseDrawable != null) { + baseDrawable.unscheduleSelf(what); + } + } + + @Override + public void setColorFilter(int color, PorterDuff.Mode mode) { + if (baseDrawable != null) { + baseDrawable.setColorFilter(color, mode); + } + } + + @Override + public void clearColorFilter() { + if (baseDrawable != null) { + baseDrawable.clearColorFilter(); + } + } + + @Override + public boolean isStateful() { + return baseDrawable != null && baseDrawable.isStateful(); + } + + @Override + public boolean setState(int[] stateSet) { + return baseDrawable != null && baseDrawable.setState(stateSet); + } + + @Override + public int[] getState() { + return baseDrawable == null ? null : baseDrawable.getState(); + } + + @Override + public Drawable getCurrent() { + return baseDrawable == null ? null : baseDrawable.getCurrent(); + } + + @Override + public boolean setVisible(boolean visible, boolean restart) { + return baseDrawable != null && baseDrawable.setVisible(visible, restart); + } + + @Override + public Region getTransparentRegion() { + return baseDrawable == null ? null : baseDrawable.getTransparentRegion(); + } + + @Override + public int getIntrinsicWidth() { + return baseDrawable == null ? 0 : baseDrawable.getIntrinsicWidth(); + } + + @Override + public int getIntrinsicHeight() { + return baseDrawable == null ? 0 : baseDrawable.getIntrinsicHeight(); + } + + @Override + public int getMinimumWidth() { + return baseDrawable == null ? 0 : baseDrawable.getMinimumWidth(); + } + + @Override + public int getMinimumHeight() { + return baseDrawable == null ? 0 : baseDrawable.getMinimumHeight(); + } + + @Override + public boolean getPadding(Rect padding) { + return baseDrawable != null && baseDrawable.getPadding(padding); + } + + @Override + public Drawable mutate() { + return baseDrawable == null ? null : baseDrawable.mutate(); + } + + @Override + public ConstantState getConstantState() { + return baseDrawable == null ? null : baseDrawable.getConstantState(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + ImageLoader imageLoader = this.getImageLoader(); + if (imageLoader != null) { + imageLoader.cancel(); + } + } +} diff --git a/app/src/main/java/org/xutils/image/GifDrawable.java b/app/src/main/java/org/xutils/image/GifDrawable.java new file mode 100644 index 0000000..563265b --- /dev/null +++ b/app/src/main/java/org/xutils/image/GifDrawable.java @@ -0,0 +1,117 @@ +package org.xutils.image; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Movie; +import android.graphics.PixelFormat; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; +import android.os.SystemClock; + +import org.xutils.common.util.LogUtil; + +public class GifDrawable extends Drawable implements Runnable, Animatable { + + private int byteCount; + private int rate = 100; + private volatile boolean running; + + private final Movie movie; + private final int duration; + private final long begin = SystemClock.uptimeMillis(); + + public GifDrawable(Movie movie, int byteCount) { + this.movie = movie; + this.byteCount = byteCount; + this.duration = movie.duration(); + } + + public int getDuration() { + return duration; + } + + public Movie getMovie() { + return movie; + } + + public int getByteCount() { + if (byteCount == 0) { + byteCount = (movie.width() * movie.height() * 3) * (5/*fake frame count*/); + } + return byteCount; + } + + public int getRate() { + return rate; + } + + public void setRate(int rate) { + this.rate = rate; + } + + @Override + public void draw(Canvas canvas) { + try { + int time = duration > 0 ? (int) (SystemClock.uptimeMillis() - begin) % duration : 0; + movie.setTime(time); + movie.draw(canvas, 0, 0); + start(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + @Override + public void start() { + if (!isRunning()) { + running = true; + run(); + } + } + + @Override + public void stop() { + if (isRunning()) { + running = false; + this.unscheduleSelf(this); + } + } + + @Override + public boolean isRunning() { + return running && duration > 0; + } + + @Override + public void run() { + if (duration > 0) { + this.invalidateSelf(); + this.scheduleSelf(this, SystemClock.uptimeMillis() + rate); + } + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public int getIntrinsicWidth() { + return movie.width(); + } + + @Override + public int getIntrinsicHeight() { + return movie.height(); + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + + @Override + public int getOpacity() { + return movie.isOpaque() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; + } + +} diff --git a/app/src/main/java/org/xutils/image/ImageAnimationHelper.java b/app/src/main/java/org/xutils/image/ImageAnimationHelper.java new file mode 100644 index 0000000..52433a2 --- /dev/null +++ b/app/src/main/java/org/xutils/image/ImageAnimationHelper.java @@ -0,0 +1,56 @@ +package org.xutils.image; + +import android.graphics.drawable.Drawable; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.DecelerateInterpolator; +import android.widget.ImageView; + +import org.xutils.common.util.LogUtil; + +import java.lang.reflect.Method; + +/** + * Created by wyouflf on 15/10/13. + * ImageView Animation Helper + */ +public final class ImageAnimationHelper { + + private final static Method cloneMethod; + + static { + Method method = null; + try { + method = Animation.class.getDeclaredMethod("clone"); + method.setAccessible(true); + } catch (Throwable ex) { + method = null; + LogUtil.w(ex.getMessage(), ex); + } + cloneMethod = method; + } + + private ImageAnimationHelper() { + } + + public static void fadeInDisplay(final ImageView imageView, Drawable drawable) { + AlphaAnimation fadeAnimation = new AlphaAnimation(0F, 1F); + fadeAnimation.setDuration(300); + fadeAnimation.setInterpolator(new DecelerateInterpolator()); + imageView.setImageDrawable(drawable); + imageView.startAnimation(fadeAnimation); + } + + public static void animationDisplay(ImageView imageView, Drawable drawable, Animation animation) { + imageView.setImageDrawable(drawable); + if (cloneMethod != null && animation != null) { + try { + imageView.startAnimation((Animation) cloneMethod.invoke(animation)); + } catch (Throwable ex) { + imageView.startAnimation(animation); + } + } else { + imageView.startAnimation(animation); + } + } +} diff --git a/app/src/main/java/org/xutils/image/ImageDecoder.java b/app/src/main/java/org/xutils/image/ImageDecoder.java new file mode 100644 index 0000000..7cedcd5 --- /dev/null +++ b/app/src/main/java/org/xutils/image/ImageDecoder.java @@ -0,0 +1,586 @@ +package org.xutils.image; + +import android.annotation.SuppressLint; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Movie; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + +import org.xutils.cache.DiskCacheEntity; +import org.xutils.cache.DiskCacheFile; +import org.xutils.cache.LruDiskCache; +import org.xutils.common.Callback; +import org.xutils.common.task.PriorityExecutor; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.x; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by wyouflf on 15/10/9. + * ImageDecoder for ImageLoader + */ +public final class ImageDecoder { + + private final static int BITMAP_DECODE_MAX_WORKER; + private final static AtomicInteger bitmapDecodeWorker = new AtomicInteger(0); + private final static Object bitmapDecodeLock = new Object(); + + private final static Object gifDecodeLock = new Object(); + private final static byte[] GIF_HEADER = new byte[]{'G', 'I', 'F'}; + + private final static Executor THUMB_CACHE_EXECUTOR = new PriorityExecutor(1, true); + private final static LruDiskCache THUMB_CACHE = LruDiskCache.getDiskCache("xUtils_img_thumb"); + + static { + int cpuCount = Runtime.getRuntime().availableProcessors(); + BITMAP_DECODE_MAX_WORKER = cpuCount > 4 ? 2 : 1; + } + + private ImageDecoder() { + } + + /*package*/ + static void clearCacheFiles() { + THUMB_CACHE.clearCacheFiles(); + } + + /** + * decode image file for ImageLoader + */ + /*package*/ + static Drawable decodeFileWithLock(final File file, + final ImageOptions options, + final Callback.Cancelable cancelable) throws IOException { + if (file == null || !file.exists() || file.length() < 1) return null; + if (cancelable != null && cancelable.isCancelled()) { + throw new Callback.CancelledException("cancelled during decode image"); + } + + Drawable result = null; + if (!options.isIgnoreGif() && isGif(file)) { + Movie movie = null; + synchronized (gifDecodeLock) { // decode with lock + movie = decodeGif(file, options, cancelable); + } + if (movie != null) { + result = new GifDrawable(movie, (int) file.length()); + ((GifDrawable) result).setRate(options.getGifRate()); + } + } else { + Bitmap bitmap = null; + { // decode with lock + boolean decodeStarted = false; + try { + synchronized (bitmapDecodeLock) { + while (bitmapDecodeWorker.get() >= BITMAP_DECODE_MAX_WORKER + && (cancelable == null || !cancelable.isCancelled())) { + try { + bitmapDecodeLock.wait(); + } catch (InterruptedException iex) { + throw new Callback.CancelledException("cancelled during decode image"); + } catch (Throwable ignored) { + } + } + } + + if (cancelable != null && cancelable.isCancelled()) { + throw new Callback.CancelledException("cancelled during decode image"); + } + + decodeStarted = true; + bitmapDecodeWorker.incrementAndGet(); + // get from thumb cache + if (options.isCompress()) { + bitmap = getThumbCache(file, options); + } + if (bitmap == null) { + bitmap = decodeBitmap(file, options, cancelable); + // save to thumb cache + if (bitmap != null && options.isCompress()) { + final Bitmap finalBitmap = bitmap; + THUMB_CACHE_EXECUTOR.execute(new Runnable() { + @Override + public void run() { + saveThumbCache(file, options, finalBitmap); + } + }); + } + } + } finally { + if (decodeStarted) { + bitmapDecodeWorker.decrementAndGet(); + } + synchronized (bitmapDecodeLock) { + bitmapDecodeLock.notifyAll(); + } + } + } + if (bitmap != null) { + result = new ReusableBitmapDrawable(x.app().getResources(), bitmap); + } + } + return result; + } + + public static boolean isGif(File file) { + FileInputStream in = null; + try { + in = new FileInputStream(file); + byte[] header = IOUtil.readBytes(in, 0, 3); + return Arrays.equals(GIF_HEADER, header); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } finally { + IOUtil.closeQuietly(in); + } + + return false; + } + + /** + * 转化文件为Bitmap. + */ + public static Bitmap decodeBitmap(File file, ImageOptions options, Callback.Cancelable cancelable) throws IOException { + {// check params + if (file == null || !file.exists() || file.length() < 1) return null; + if (options == null) { + options = ImageOptions.DEFAULT; + } + if (options.getMaxWidth() <= 0 || options.getMaxHeight() <= 0) { + options.optimizeMaxSize(null); + } + } + + Bitmap result = null; + try { + if (cancelable != null && cancelable.isCancelled()) { + throw new Callback.CancelledException("cancelled during decode image"); + } + + // prepare bitmap options + final BitmapFactory.Options bitmapOps = new BitmapFactory.Options(); + bitmapOps.inJustDecodeBounds = true; + bitmapOps.inPurgeable = true; + bitmapOps.inInputShareable = true; + BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOps); + bitmapOps.inJustDecodeBounds = false; + bitmapOps.inPreferredConfig = options.getConfig(); + int rotateAngle = 0; + int rawWidth = bitmapOps.outWidth; + int rawHeight = bitmapOps.outHeight; + int optionWith = options.getWidth(); + int optionHeight = options.getHeight(); + if (options.isAutoRotate()) { + rotateAngle = getRotateAngle(file.getAbsolutePath()); + if ((rotateAngle / 90) % 2 == 1) { + rawWidth = bitmapOps.outHeight; + rawHeight = bitmapOps.outWidth; + } + } + if (!options.isCrop() && optionWith > 0 && optionHeight > 0) { + if ((rotateAngle / 90) % 2 == 1) { + bitmapOps.outWidth = optionHeight; + bitmapOps.outHeight = optionWith; + } else { + bitmapOps.outWidth = optionWith; + bitmapOps.outHeight = optionHeight; + } + } + bitmapOps.inSampleSize = calculateSampleSize( + rawWidth, rawHeight, + options.getMaxWidth(), options.getMaxHeight()); + + if (cancelable != null && cancelable.isCancelled()) { + throw new Callback.CancelledException("cancelled during decode image"); + } + + // decode file + Bitmap bitmap = null; + bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOps); + if (bitmap == null) { + throw new IOException("decode image error"); + } + + { // 旋转和缩放处理 + if (cancelable != null && cancelable.isCancelled()) { + throw new Callback.CancelledException("cancelled during decode image"); + } + if (rotateAngle != 0) { + bitmap = rotate(bitmap, rotateAngle, true); + } + if (cancelable != null && cancelable.isCancelled()) { + throw new Callback.CancelledException("cancelled during decode image"); + } + if (options.isCrop() && optionWith > 0 && optionHeight > 0) { + bitmap = cut2ScaleSize(bitmap, optionWith, optionHeight, true); + } + } + + if (bitmap == null) { + throw new IOException("decode image error"); + } + + { // 圆角和方块处理 + if (cancelable != null && cancelable.isCancelled()) { + throw new Callback.CancelledException("cancelled during decode image"); + } + if (options.isCircular()) { + bitmap = cut2Circular(bitmap, true); + } else if (options.getRadius() > 0) { + bitmap = cut2RoundCorner(bitmap, options.getRadius(), options.isSquare(), true); + } else if (options.isSquare()) { + bitmap = cut2Square(bitmap, true); + } + } + + if (bitmap == null) { + throw new IOException("decode image error"); + } + + result = bitmap; + } catch (Callback.CancelledException ex) { + throw ex; + } catch (IOException ex) { + throw ex; + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + result = null; + } + + return result; + } + + /** + * 转换文件为Movie, 可用于创建GifDrawable. + */ + public static Movie decodeGif(File file, ImageOptions options, Callback.Cancelable cancelable) throws IOException { + {// check params + if (file == null || !file.exists() || file.length() < 1) return null; + /*if (options == null) { + options = ImageOptions.DEFAULT; // not use + } + if (options.getMaxWidth() <= 0 || options.getMaxHeight() <= 0) { + options.optimizeMaxSize(null); + }*/ + } + + try { + if (cancelable != null && cancelable.isCancelled()) { + throw new Callback.CancelledException("cancelled during decode image"); + } + Movie movie = Movie.decodeFile(file.getAbsolutePath()); + if (movie == null) { + throw new IOException("decode image error"); + } + return movie; + } catch (Callback.CancelledException ex) { + throw ex; + } catch (IOException ex) { + throw ex; + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + return null; + } + } + + /** + * 计算压缩采样倍数 + * + * @param rawWidth 图片宽度 + * @param rawHeight 图片高度 + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @return 压缩采样倍数 + */ + public static int calculateSampleSize(final int rawWidth, final int rawHeight, + final int maxWidth, final int maxHeight) { + int sampleSize = 1; + + if (rawWidth > maxWidth || rawHeight > maxHeight) { + if (rawWidth > rawHeight) { + sampleSize = Math.round((float) rawHeight / (float) maxHeight); + } else { + sampleSize = Math.round((float) rawWidth / (float) maxWidth); + } + + if (sampleSize < 1) { + sampleSize = 1; + } + + final float totalPixels = rawWidth * rawHeight; + + final float maxTotalPixels = maxWidth * maxHeight * 2; + + while (totalPixels / (sampleSize * sampleSize) > maxTotalPixels) { + sampleSize++; + } + } + return sampleSize; + } + + /** + * 裁剪方形图片 + * + * @param recycleSource 是否裁剪成功后销毁原图 + */ + public static Bitmap cut2Square(Bitmap source, boolean recycleSource) { + int width = source.getWidth(); + int height = source.getHeight(); + if (width == height) { + return source; + } + + int squareWith = Math.min(width, height); + Bitmap result = Bitmap.createBitmap(source, (width - squareWith) / 2, + (height - squareWith) / 2, squareWith, squareWith); + if (result != null) { + if (recycleSource && result != source) { + source.recycle(); + source = null; + } + } else { + result = source; + } + return result; + } + + /** + * 裁剪圆形图片 + * + * @param recycleSource 是否裁剪成功后销毁原图 + */ + public static Bitmap cut2Circular(Bitmap source, boolean recycleSource) { + int width = source.getWidth(); + int height = source.getHeight(); + int diameter = Math.min(width, height); + Paint paint = new Paint(); + paint.setAntiAlias(true); + Bitmap result = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888); + if (result != null) { + Canvas canvas = new Canvas(result); + canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(source, (diameter - width) / 2, (diameter - height) / 2, paint); + if (recycleSource) { + source.recycle(); + source = null; + } + } else { + result = source; + } + return result; + } + + /** + * 裁剪圆角 + * + * @param recycleSource 是否裁剪成功后销毁原图 + */ + public static Bitmap cut2RoundCorner(Bitmap source, int radius, boolean isSquare, boolean recycleSource) { + if (radius <= 0) return source; + + int sourceWidth = source.getWidth(); + int sourceHeight = source.getHeight(); + int targetWidth = sourceWidth; + int targetHeight = sourceHeight; + if (isSquare) { + targetWidth = targetHeight = Math.min(sourceWidth, sourceHeight); + } + + Paint paint = new Paint(); + paint.setAntiAlias(true); + Bitmap result = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888); + if (result != null) { + Canvas canvas = new Canvas(result); + RectF rect = new RectF(0, 0, targetWidth, targetHeight); + canvas.drawRoundRect(rect, radius, radius, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(source, + (targetWidth - sourceWidth) / 2, (targetHeight - sourceHeight) / 2, paint); + if (recycleSource) { + source.recycle(); + source = null; + } + } else { + result = source; + } + return result; + } + + /** + * 裁剪并缩放至指定大小 + * + * @param recycleSource 是否裁剪成功后销毁原图 + */ + public static Bitmap cut2ScaleSize(Bitmap source, int dstWidth, int dstHeight, boolean recycleSource) { + final int width = source.getWidth(); + final int height = source.getHeight(); + if (width == dstWidth && height == dstHeight) { + return source; + } + + // scale + Matrix m = new Matrix(); + int l = 0, t = 0, r = width, b = height; + { + float sx = dstWidth / (float) width; + float sy = dstHeight / (float) height; + + if (sx > sy) { + sy = sx; + l = 0; + r = width; + t = (int) ((height - dstHeight / sx) / 2); + b = (int) ((height + dstHeight / sx) / 2); + } else { + sx = sy; + l = (int) ((width - dstWidth / sx) / 2); + r = (int) ((width + dstWidth / sx) / 2); + t = 0; + b = height; + } + m.setScale(sx, sy); + } + + Bitmap result = Bitmap.createBitmap(source, l, t, r - l, b - t, m, true); + + if (result != null) { + if (recycleSource && result != source) { + source.recycle(); + source = null; + } + } else { + result = source; + } + return result; + } + + /** + * 旋转图片 + * + * @param recycleSource 是否旋转成功后销毁原图 + */ + public static Bitmap rotate(Bitmap source, int angle, boolean recycleSource) { + Bitmap result = null; + + if (angle != 0) { + + Matrix m = new Matrix(); + m.setRotate(angle); + try { + result = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), m, true); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + if (result != null) { + if (recycleSource && result != source) { + source.recycle(); + source = null; + } + } else { + result = source; + } + return result; + } + + /** + * 获取图片旋转角度 + * + * @param filePath 图片文件路径 + * @return 需要旋转的角度 + */ + @SuppressLint("ExifInterface") + public static int getRotateAngle(String filePath) { + int angle = 0; + try { + android.media.ExifInterface exif = new android.media.ExifInterface(filePath); + int orientation = exif.getAttributeInt( + android.media.ExifInterface.TAG_ORIENTATION, + android.media.ExifInterface.ORIENTATION_UNDEFINED); + switch (orientation) { + case android.media.ExifInterface.ORIENTATION_ROTATE_90: + angle = 90; + break; + case android.media.ExifInterface.ORIENTATION_ROTATE_180: + angle = 180; + break; + case android.media.ExifInterface.ORIENTATION_ROTATE_270: + angle = 270; + break; + default: + angle = 0; + break; + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + return angle; + } + + /** + * 根据文件的修改时间和图片的属性保存缩略图 + */ + private static void saveThumbCache(File file, ImageOptions options, Bitmap thumbBitmap) { + DiskCacheEntity entity = new DiskCacheEntity(); + entity.setKey( + file.getAbsolutePath() + "@" + file.lastModified() + options.toString()); + DiskCacheFile cacheFile = null; + OutputStream out = null; + try { + cacheFile = THUMB_CACHE.createDiskCacheFile(entity); + if (cacheFile != null) { + out = new FileOutputStream(cacheFile); + thumbBitmap.compress(Bitmap.CompressFormat.PNG, 80, out); + out.flush(); + cacheFile = cacheFile.commit(); + } + } catch (Throwable ex) { + IOUtil.deleteFileOrDir(cacheFile); + LogUtil.w(ex.getMessage(), ex); + } finally { + IOUtil.closeQuietly(cacheFile); + IOUtil.closeQuietly(out); + } + } + + /** + * 根据文件的修改时间和图片的属性获取缩略图 + */ + private static Bitmap getThumbCache(File file, ImageOptions options) { + DiskCacheFile cacheFile = null; + try { + cacheFile = THUMB_CACHE.getDiskCacheFile( + file.getAbsolutePath() + "@" + file.lastModified() + options.toString()); + if (cacheFile != null && cacheFile.exists()) { + BitmapFactory.Options bitmapOps = new BitmapFactory.Options(); + bitmapOps.inJustDecodeBounds = false; + bitmapOps.inPurgeable = true; + bitmapOps.inInputShareable = true; + bitmapOps.inPreferredConfig = Bitmap.Config.ARGB_8888; + return BitmapFactory.decodeFile(cacheFile.getAbsolutePath(), bitmapOps); + } + } catch (Throwable ex) { + LogUtil.w(ex.getMessage(), ex); + } finally { + IOUtil.closeQuietly(cacheFile); + } + return null; + } +} diff --git a/app/src/main/java/org/xutils/image/ImageLoader.java b/app/src/main/java/org/xutils/image/ImageLoader.java new file mode 100644 index 0000000..12eb6f9 --- /dev/null +++ b/app/src/main/java/org/xutils/image/ImageLoader.java @@ -0,0 +1,642 @@ +package org.xutils.image; + +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.View; +import android.view.animation.Animation; +import android.widget.ImageView; + +import org.xutils.cache.LruCache; +import org.xutils.cache.LruDiskCache; +import org.xutils.common.Callback; +import org.xutils.common.task.Priority; +import org.xutils.common.task.PriorityExecutor; +import org.xutils.common.util.IOUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.ex.FileLockedException; +import org.xutils.http.RequestParams; +import org.xutils.x; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Created by wyouflf on 15/10/9. + * 图片加载控制 + */ +/*package*/ final class ImageLoader implements + Callback.PrepareCallback, + Callback.CacheCallback, + Callback.ProgressCallback, + Callback.TypedCallback, + Callback.Cancelable { + + private MemCacheKey key; + private ImageOptions options; + private WeakReference viewRef; + private int fileLockedExceptionRetryCount = 0; + + private final static AtomicLong SEQ_SEEK = new AtomicLong(0); + private final long seq = SEQ_SEEK.incrementAndGet(); + + private volatile boolean stopped = false; + private volatile boolean cancelled = false; + private volatile boolean skipOnWaitingCallback = false; + private volatile boolean skipOnFinishedCallback = false; + private Cancelable httpCancelable; + private CommonCallback callback; + private PrepareCallback prepareCallback; + private CacheCallback cacheCallback; + private ProgressCallback progressCallback; + + private final static String DISK_CACHE_DIR_NAME = "xUtils_img"; + private final static Executor EXECUTOR = new PriorityExecutor(10, false); + private final static int MEM_CACHE_MIN_SIZE = 1024 * 1024 * 4; // 4M + private final static LruCache MEM_CACHE = + new LruCache(MEM_CACHE_MIN_SIZE) { + private boolean deepClear = false; + + @Override + protected int sizeOf(MemCacheKey key, Drawable value) { + if (value instanceof BitmapDrawable) { + Bitmap bitmap = ((BitmapDrawable) value).getBitmap(); + return bitmap == null ? 0 : bitmap.getByteCount(); + } else if (value instanceof GifDrawable) { + return ((GifDrawable) value).getByteCount(); + } + return super.sizeOf(key, value); + } + + @Override + public void trimToSize(int maxSize) { + if (maxSize < 0) { + deepClear = true; + } + super.trimToSize(maxSize); + deepClear = false; + } + + @Override + protected void entryRemoved(boolean evicted, MemCacheKey key, Drawable oldValue, Drawable newValue) { + super.entryRemoved(evicted, key, oldValue, newValue); + if (evicted && deepClear && oldValue instanceof ReusableDrawable) { + ((ReusableDrawable) oldValue).setMemCacheKey(null); + } + } + }; + + static { + int memClass = ((ActivityManager) x.app() + .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass(); + + // Use 1/8th of the available memory for this memory cache. + int cacheSize = 1024 * 1024 * memClass / 8; + if (cacheSize < MEM_CACHE_MIN_SIZE) { + cacheSize = MEM_CACHE_MIN_SIZE; + } + MEM_CACHE.resize(cacheSize); + } + + private ImageLoader() { + } + + /*package*/ + static void clearMemCache() { + MEM_CACHE.evictAll(); + } + + /*package*/ + static void clearCacheFiles() { + LruDiskCache.getDiskCache(DISK_CACHE_DIR_NAME).clearCacheFiles(); + } + + private final static HashMap FAKE_IMG_MAP = new HashMap(); + + /** + * load from Network or DiskCache, invoke in any thread. + */ + /*package*/ + static Cancelable doLoadDrawable(final String url, + final ImageOptions options, + final CommonCallback callback) { + if (TextUtils.isEmpty(url)) { + postArgsException(null, options, "url is null", callback); + return null; + } + + FakeImageView fakeImageView = new FakeImageView(); + return doBind(fakeImageView, url, options, 0, callback); + } + + /** + * load from Network or DiskCache, invoke in any thread. + */ + /*package*/ + static Cancelable doLoadFile(final String url, + final ImageOptions options, + final CacheCallback callback) { + if (TextUtils.isEmpty(url)) { + postArgsException(null, options, "url is null", callback); + return null; + } + + RequestParams params = createRequestParams(null, url, options); + return x.http().get(params, callback); + } + + /** + * load from Network or DiskCache, invoke in ui thread. + */ + /*package*/ + static Cancelable doBind(final ImageView view, + final String url, + final ImageOptions options, + final int fileLockedExceptionRetryCount, + final CommonCallback callback) { + + // check params + ImageOptions localOptions = options; + { + if (view == null) { + postArgsException(null, localOptions, "view is null", callback); + return null; + } + + if (TextUtils.isEmpty(url)) { + postArgsException(view, localOptions, "url is null", callback); + return null; + } + + if (localOptions == null) { + localOptions = ImageOptions.DEFAULT; + } + localOptions.optimizeMaxSize(view); + } + + // stop the old loader + MemCacheKey key = new MemCacheKey(url, localOptions); + Drawable oldDrawable = view.getDrawable(); + if (oldDrawable instanceof AsyncDrawable) { + ImageLoader loader = ((AsyncDrawable) oldDrawable).getImageLoader(); + if (loader != null && !loader.stopped) { + if (key.equals(loader.key)) { + // repetitive url and options binding to the same View. + // not need callback to ui. + return null; + } else { + loader.cancel(); + } + } + } else if (oldDrawable instanceof ReusableDrawable) { + MemCacheKey oldKey = ((ReusableDrawable) oldDrawable).getMemCacheKey(); + if (oldKey != null && oldKey.equals(key)) { + MEM_CACHE.put(key, oldDrawable); + } + } + + // load from Memory Cache + Drawable memDrawable = null; + if (localOptions.isUseMemCache()) { + memDrawable = MEM_CACHE.get(key); + if (memDrawable instanceof BitmapDrawable) { + Bitmap bitmap = ((BitmapDrawable) memDrawable).getBitmap(); + if (bitmap == null || bitmap.isRecycled()) { + memDrawable = null; + } + } + } + if (memDrawable != null) { // has mem cache + boolean trustMemCache = false; + try { + if (callback instanceof ProgressCallback) { + try { + ((ProgressCallback) callback).onWaiting(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + if (callback instanceof CacheCallback) { + try { + // 是否信任内存缓存. onStart 之后再次调用 onCache 时, 入参是磁盘缓存. + trustMemCache = ((CacheCallback) callback).onCache(memDrawable); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } else { + trustMemCache = true; + } + + // hit mem cache + if (trustMemCache) { + view.setScaleType(localOptions.getImageScaleType()); + view.setImageDrawable(memDrawable); + if (callback != null) { + try { + callback.onSuccess(memDrawable); + } catch (Throwable ex) { + callback.onError(ex, true); + } + } + // goto finally + } else { + // not trust the cache + // load from Network or DiskCache + ImageLoader loader = new ImageLoader(); + loader.fileLockedExceptionRetryCount = fileLockedExceptionRetryCount; + loader.skipOnWaitingCallback = true; + return loader.doLoadRequest(view, url, localOptions, callback); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + // try load from Network or DiskCache + trustMemCache = false; + ImageLoader loader = new ImageLoader(); + loader.fileLockedExceptionRetryCount = fileLockedExceptionRetryCount; + loader.skipOnWaitingCallback = true; + return loader.doLoadRequest(view, url, localOptions, callback); + } finally { + if (trustMemCache && callback != null) { + try { + callback.onFinished(); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } else { /* memDrawable == null */ + // load from Network or DiskCache + ImageLoader loader = new ImageLoader(); + loader.fileLockedExceptionRetryCount = fileLockedExceptionRetryCount; + return loader.doLoadRequest(view, url, localOptions, callback); + } + return null; + } + + /** + * load from Network or DiskCache + */ + private Cancelable doLoadRequest(ImageView view, + String url, + ImageOptions options, + CommonCallback callback) { + + this.viewRef = new WeakReference(view); + this.options = options; + this.key = new MemCacheKey(url, options); + this.callback = callback; + if (callback instanceof ProgressCallback) { + this.progressCallback = (ProgressCallback) callback; + } + if (callback instanceof PrepareCallback) { + this.prepareCallback = (PrepareCallback) callback; + } + if (callback instanceof CacheCallback) { + this.cacheCallback = (CacheCallback) callback; + } + + // set loadingDrawable + Drawable loadingDrawable = view.getDrawable(); + if (loadingDrawable == null || options.isForceLoadingDrawable()) { + loadingDrawable = options.getLoadingDrawable(view); + view.setScaleType(options.getPlaceholderScaleType()); + } + view.setImageDrawable(new AsyncDrawable(this, loadingDrawable)); + + // request + RequestParams params = createRequestParams(view.getContext(), url, options); + if (view instanceof FakeImageView) { + synchronized (FAKE_IMG_MAP) { + FAKE_IMG_MAP.put(view.hashCode() + url, (FakeImageView) view); + } + } + return httpCancelable = x.http().get(params, this); + } + + @Override + public void cancel() { + stopped = true; + cancelled = true; + if (httpCancelable != null) { + httpCancelable.cancel(); + } + } + + @Override + public boolean isCancelled() { + return cancelled || !validView4Callback(false); + } + + @Override + public void onWaiting() { + if (!skipOnWaitingCallback && progressCallback != null) { + progressCallback.onWaiting(); + } + } + + @Override + public void onStarted() { + if (validView4Callback(true) && progressCallback != null) { + progressCallback.onStarted(); + } + } + + @Override + public void onLoading(long total, long current, boolean isDownloading) { + if (validView4Callback(true) && progressCallback != null) { + progressCallback.onLoading(total, current, isDownloading); + } + } + + private static final Type loadType = File.class; + + @Override + public Type getLoadType() { + return loadType; + } + + @Override + public Drawable prepare(File rawData) throws Throwable { + if (!validView4Callback(true)) return null; + + if (!rawData.exists()) { + throw new FileNotFoundException(rawData.getAbsolutePath()); + } + + try { + Drawable result = null; + if (prepareCallback != null) { + result = prepareCallback.prepare(rawData); + } + if (result == null) { + result = ImageDecoder.decodeFileWithLock(rawData, options, this); + } + if (result != null) { + if (result instanceof ReusableDrawable) { + ((ReusableDrawable) result).setMemCacheKey(key); + MEM_CACHE.put(key, result); + } + } + return result; + } catch (IOException ex) { + IOUtil.deleteFileOrDir(rawData); + throw ex; + } + } + + private boolean hasCache = false; + + @Override + public boolean onCache(Drawable result) { + if (!validView4Callback(true)) return false; + + if (result != null) { + hasCache = true; + setSuccessDrawable4Callback(result); + if (cacheCallback != null) { + return cacheCallback.onCache(result); + } else if (callback != null) { + callback.onSuccess(result); + return true; + } + return true; + } + + return false; + } + + @Override + public void onSuccess(Drawable result) { + if (!validView4Callback(!hasCache)) return; + + if (result != null) { + setSuccessDrawable4Callback(result); + if (callback != null) { + callback.onSuccess(result); + } + } + } + + @Override + public void onError(Throwable ex, boolean isOnCallback) { + stopped = true; + if (!validView4Callback(false)) return; + + fileLockedExceptionRetryCount++; + if (ex instanceof FileLockedException && fileLockedExceptionRetryCount < 1000/*max*/) { + LogUtil.d("ImageFileLocked: " + key.url); + x.task().postDelayed(new Runnable() { + @Override + public void run() { + ImageView imageView = viewRef.get(); + if (imageView != null) { + doBind(imageView, key.url, options, fileLockedExceptionRetryCount, callback); + } else { + ImageLoader.this.onFinished(); + } + } + }, 10); + skipOnFinishedCallback = true; + } else { + LogUtil.e(key.url, ex); + setErrorDrawable4Callback(); + if (callback != null) { + callback.onError(ex, isOnCallback); + } + } + } + + @Override + public void onCancelled(CancelledException cex) { + stopped = true; + if (!validView4Callback(false)) return; + + if (callback != null) { + callback.onCancelled(cex); + } + } + + @Override + public void onFinished() { + stopped = true; + if (skipOnFinishedCallback) return; + + ImageView view = viewRef.get(); + if (view instanceof FakeImageView) { + synchronized (FAKE_IMG_MAP) { + FAKE_IMG_MAP.remove(view.hashCode() + key.url); + } + } + + if (callback != null) { + callback.onFinished(); + } + } + + private static RequestParams createRequestParams(Context context, String url, ImageOptions options) { + RequestParams params = new RequestParams(url); + if (context != null) { + params.setContext(context); + } + params.setCacheDirName(DISK_CACHE_DIR_NAME); + params.setConnectTimeout(1000 * 8); + params.setPriority(Priority.BG_LOW); + params.setExecutor(EXECUTOR); + params.setCancelFast(true); + params.setUseCookie(false); + if (options != null) { + ImageOptions.ParamsBuilder paramsBuilder = options.getParamsBuilder(); + if (paramsBuilder != null) { + params = paramsBuilder.buildParams(params, options); + } + } + return params; + } + + private boolean validView4Callback(boolean forceValidAsyncDrawable) { + final ImageView view = viewRef.get(); + if (view != null) { + Drawable otherDrawable = view.getDrawable(); + if (otherDrawable instanceof AsyncDrawable) { + ImageLoader otherLoader = ((AsyncDrawable) otherDrawable).getImageLoader(); + if (otherLoader != null) { + if (otherLoader == this) { + return true; + } else { + if (this.seq > otherLoader.seq) { + otherLoader.cancel(); + return true; + } else { + this.cancel(); + return false; + } + } + } + } else if (forceValidAsyncDrawable) { + this.cancel(); + return false; + } + return true; + } + return false; + } + + private void setSuccessDrawable4Callback(final Drawable drawable) { + final ImageView view = viewRef.get(); + if (view != null) { + view.setScaleType(options.getImageScaleType()); + if (drawable instanceof GifDrawable) { + if (view.getScaleType() == ImageView.ScaleType.CENTER) { + view.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + } + view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + if (options.getAnimation() != null) { + ImageAnimationHelper.animationDisplay(view, drawable, options.getAnimation()); + } else if (options.isFadeIn()) { + ImageAnimationHelper.fadeInDisplay(view, drawable); + } else { + view.setImageDrawable(drawable); + } + } + } + + private void setErrorDrawable4Callback() { + final ImageView view = viewRef.get(); + if (view != null) { + Drawable drawable = options.getFailureDrawable(view); + view.setScaleType(options.getPlaceholderScaleType()); + view.setImageDrawable(drawable); + } + } + + private static void postArgsException( + final ImageView view, final ImageOptions options, + final String exMsg, final CommonCallback callback) { + x.task().autoPost(new Runnable() { + @Override + public void run() { + try { + if (callback instanceof ProgressCallback) { + ((ProgressCallback) callback).onWaiting(); + } + if (view != null && options != null) { + view.setScaleType(options.getPlaceholderScaleType()); + view.setImageDrawable(options.getFailureDrawable(view)); + } + if (callback != null) { + callback.onError(new IllegalArgumentException(exMsg), false); + } + } catch (Throwable ex) { + if (callback != null) { + try { + callback.onError(ex, true); + } catch (Throwable throwable) { + LogUtil.e(throwable.getMessage(), throwable); + } + } + } finally { + if (callback != null) { + try { + callback.onFinished(); + } catch (Throwable throwable) { + LogUtil.e(throwable.getMessage(), throwable); + } + } + } + } + }); + } + + @SuppressLint({"ViewConstructor", "AppCompatCustomView"}) + private final static class FakeImageView extends ImageView { + private final int hashCode; + private Drawable drawable; + private final static AtomicInteger hashCodeSeed = new AtomicInteger(0); + + public FakeImageView() { + super(x.app()); + hashCode = hashCodeSeed.incrementAndGet(); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public void setImageDrawable(Drawable drawable) { + this.drawable = drawable; + } + + @Override + public Drawable getDrawable() { + return drawable; + } + + @Override + public void setLayerType(int layerType, Paint paint) { + } + + @Override + public void setScaleType(ScaleType scaleType) { + } + + @Override + public void startAnimation(Animation animation) { + } + } +} diff --git a/app/src/main/java/org/xutils/image/ImageManagerImpl.java b/app/src/main/java/org/xutils/image/ImageManagerImpl.java new file mode 100644 index 0000000..bde8914 --- /dev/null +++ b/app/src/main/java/org/xutils/image/ImageManagerImpl.java @@ -0,0 +1,95 @@ +package org.xutils.image; + +import android.graphics.drawable.Drawable; +import android.widget.ImageView; + +import org.xutils.ImageManager; +import org.xutils.common.Callback; +import org.xutils.x; + +import java.io.File; + +/** + * Created by wyouflf on 15/10/9. + */ +public final class ImageManagerImpl implements ImageManager { + + private static final Object lock = new Object(); + private static volatile ImageManagerImpl instance; + + private ImageManagerImpl() { + } + + public static void registerInstance() { + if (instance == null) { + synchronized (lock) { + if (instance == null) { + instance = new ImageManagerImpl(); + } + } + } + x.Ext.setImageManager(instance); + } + + + @Override + public void bind(final ImageView view, final String url) { + x.task().autoPost(new Runnable() { + @Override + public void run() { + ImageLoader.doBind(view, url, null, 0, null); + } + }); + } + + @Override + public void bind(final ImageView view, final String url, final ImageOptions options) { + x.task().autoPost(new Runnable() { + @Override + public void run() { + ImageLoader.doBind(view, url, options, 0, null); + } + }); + } + + @Override + public void bind(final ImageView view, final String url, final Callback.CommonCallback callback) { + x.task().autoPost(new Runnable() { + @Override + public void run() { + ImageLoader.doBind(view, url, null, 0, callback); + } + }); + } + + @Override + public void bind(final ImageView view, final String url, final ImageOptions options, final Callback.CommonCallback callback) { + x.task().autoPost(new Runnable() { + @Override + public void run() { + ImageLoader.doBind(view, url, options, 0, callback); + } + }); + } + + @Override + public Callback.Cancelable loadDrawable(String url, ImageOptions options, Callback.CommonCallback callback) { + return ImageLoader.doLoadDrawable(url, options, callback); + } + + @Override + public Callback.Cancelable loadFile(String url, ImageOptions options, Callback.CacheCallback callback) { + return ImageLoader.doLoadFile(url, options, callback); + } + + @Override + public void clearMemCache() { + ImageLoader.clearMemCache(); + } + + @Override + public void clearCacheFiles() { + ImageLoader.clearCacheFiles(); + ImageDecoder.clearCacheFiles(); + } +} diff --git a/app/src/main/java/org/xutils/image/ImageOptions.java b/app/src/main/java/org/xutils/image/ImageOptions.java new file mode 100644 index 0000000..9a33fbd --- /dev/null +++ b/app/src/main/java/org/xutils/image/ImageOptions.java @@ -0,0 +1,414 @@ +package org.xutils.image; + +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.ImageView; + +import org.xutils.common.util.DensityUtil; +import org.xutils.common.util.LogUtil; +import org.xutils.http.RequestParams; + +/** + * Created by wyouflf on 15/8/21. + * 图片加载参数 + */ +public class ImageOptions { + + public final static ImageOptions DEFAULT = new ImageOptions(); + + // region ###################### decode options (equals & hashcode prop) ################ + private int maxWidth = 0; + private int maxHeight = 0; + private int width = 0; // 小于0时不采样压缩. 等于0时自动识别ImageView的宽高和maxWidth. + private int height = 0; // 小于0时不采样压缩. 等于0时自动识别ImageView的宽高和maxHeight. + private boolean crop = false; // crop to (width, height) + + private int radius = 0; + private boolean square = false; + private boolean circular = false; + private boolean autoRotate = false; + private boolean compress = true; + private Bitmap.Config config = Bitmap.Config.RGB_565; + + // gif option + private boolean ignoreGif = true; + private int gifRate = 100; + // end region ########################################## decode options ################# + + // region ############# display options + private int loadingDrawableId = 0; + private int failureDrawableId = 0; + private Drawable loadingDrawable = null; + private Drawable failureDrawable = null; + private boolean forceLoadingDrawable = true; + + private ImageView.ScaleType placeholderScaleType = ImageView.ScaleType.CENTER_INSIDE; + private ImageView.ScaleType imageScaleType = ImageView.ScaleType.CENTER_CROP; + + private boolean fadeIn = false; + private Animation animation = null; + // end region ############ display options + + // extends + private boolean useMemCache = true; + private ParamsBuilder paramsBuilder; + + protected ImageOptions() { + } + + /*package*/ + final void optimizeMaxSize(ImageView view) { + if (width > 0 && height > 0) { + maxWidth = width; + maxHeight = height; + return; + } + + int screenWidth = DensityUtil.getScreenWidth(); + int screenHeight = DensityUtil.getScreenHeight(); + + if (this == DEFAULT) { + maxWidth = width = screenWidth * 3 / 2; + maxHeight = height = screenHeight * 3 / 2; + return; + } + + if (width < 0) { + maxWidth = screenWidth * 3 / 2; + compress = false; + } + if (height < 0) { + maxHeight = screenHeight * 3 / 2; + compress = false; + } + + if (view == null && maxWidth <= 0 && maxHeight <= 0) { + maxWidth = screenWidth; + maxHeight = screenHeight; + } else { + int tempWidth = maxWidth; + int tempHeight = maxHeight; + + if (view != null) { + final ViewGroup.LayoutParams params = view.getLayoutParams(); + if (params != null) { + + if (tempWidth <= 0) { + if (params.width > 0) { + tempWidth = params.width; + if (this.width <= 0) { + this.width = tempWidth; + } + } else if (params.width != ViewGroup.LayoutParams.WRAP_CONTENT) { + tempWidth = view.getWidth(); + } + } + + if (tempHeight <= 0) { + if (params.height > 0) { + tempHeight = params.height; + if (this.height <= 0) { + this.height = tempHeight; + } + } else if (params.height != ViewGroup.LayoutParams.WRAP_CONTENT) { + tempHeight = view.getHeight(); + } + } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + if (tempWidth <= 0) tempWidth = view.getMaxWidth(); + if (tempHeight <= 0) tempHeight = view.getMaxHeight(); + } + } + + if (tempWidth <= 0) tempWidth = screenWidth; + if (tempHeight <= 0) tempHeight = screenHeight; + + maxWidth = tempWidth; + maxHeight = tempHeight; + } + } + + public int getMaxWidth() { + return maxWidth; + } + + public int getMaxHeight() { + return maxHeight; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public boolean isCrop() { + return crop; + } + + public int getRadius() { + return radius; + } + + public boolean isSquare() { + return square; + } + + public boolean isCircular() { + return circular; + } + + public boolean isIgnoreGif() { + return ignoreGif; + } + + public int getGifRate() { + return gifRate; + } + + public boolean isAutoRotate() { + return autoRotate; + } + + public boolean isCompress() { + return compress; + } + + public Bitmap.Config getConfig() { + return config; + } + + public Drawable getLoadingDrawable(ImageView view) { + if (loadingDrawable == null && loadingDrawableId > 0 && view != null) { + try { + loadingDrawable = view.getResources().getDrawable(loadingDrawableId); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + return loadingDrawable; + } + + public Drawable getFailureDrawable(ImageView view) { + if (failureDrawable == null && failureDrawableId > 0 && view != null) { + try { + failureDrawable = view.getResources().getDrawable(failureDrawableId); + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + return failureDrawable; + } + + public boolean isFadeIn() { + return fadeIn; + } + + public Animation getAnimation() { + return animation; + } + + public ImageView.ScaleType getPlaceholderScaleType() { + return placeholderScaleType; + } + + public ImageView.ScaleType getImageScaleType() { + return imageScaleType; + } + + public boolean isForceLoadingDrawable() { + return forceLoadingDrawable; + } + + public boolean isUseMemCache() { + return useMemCache; + } + + public ParamsBuilder getParamsBuilder() { + return paramsBuilder; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ImageOptions options = (ImageOptions) o; + + if (maxWidth != options.maxWidth) return false; + if (maxHeight != options.maxHeight) return false; + if (width != options.width) return false; + if (height != options.height) return false; + if (crop != options.crop) return false; + if (radius != options.radius) return false; + if (square != options.square) return false; + if (circular != options.circular) return false; + if (autoRotate != options.autoRotate) return false; + if (compress != options.compress) return false; + return config == options.config; + + } + + @Override + public int hashCode() { + int result = maxWidth; + result = 31 * result + maxHeight; + result = 31 * result + width; + result = 31 * result + height; + result = 31 * result + (crop ? 1 : 0); + result = 31 * result + radius; + result = 31 * result + (square ? 1 : 0); + result = 31 * result + (circular ? 1 : 0); + result = 31 * result + (autoRotate ? 1 : 0); + result = 31 * result + (compress ? 1 : 0); + result = 31 * result + (config != null ? config.hashCode() : 0); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("_"); + sb.append(maxWidth).append("_"); + sb.append(maxHeight).append("_"); + sb.append(width).append("_"); + sb.append(height).append("_"); + sb.append(radius).append("_"); + sb.append(config).append("_"); + sb.append(crop ? 1 : 0).append(square ? 1 : 0).append(circular ? 1 : 0); + sb.append(autoRotate ? 1 : 0).append(compress ? 1 : 0); + return sb.toString(); + } + + public interface ParamsBuilder { + RequestParams buildParams(RequestParams params, ImageOptions options); + } + + public static class Builder { + + protected ImageOptions options; + + public Builder() { + newImageOptions(); + } + + protected void newImageOptions() { + options = new ImageOptions(); + } + + public ImageOptions build() { + return options; + } + + /** + * 小于0时不采样压缩. 等于0时自动识别ImageView的宽高和(maxWidth, maxHeight). + */ + public Builder setSize(int width, int height) { + options.width = width; + options.height = height; + return this; + } + + public Builder setCrop(boolean crop) { + options.crop = crop; + return this; + } + + public Builder setRadius(int radius) { + options.radius = radius; + return this; + } + + public Builder setSquare(boolean square) { + options.square = square; + return this; + } + + public Builder setCircular(boolean circular) { + options.circular = circular; + return this; + } + + public Builder setAutoRotate(boolean autoRotate) { + options.autoRotate = autoRotate; + return this; + } + + public Builder setConfig(Bitmap.Config config) { + options.config = config; + return this; + } + + public Builder setIgnoreGif(boolean ignoreGif) { + options.ignoreGif = ignoreGif; + return this; + } + + public Builder setGifRate(int rate) { + options.gifRate = rate; + return this; + } + + public Builder setLoadingDrawableId(int loadingDrawableId) { + options.loadingDrawableId = loadingDrawableId; + return this; + } + + public Builder setLoadingDrawable(Drawable loadingDrawable) { + options.loadingDrawable = loadingDrawable; + return this; + } + + public Builder setFailureDrawableId(int failureDrawableId) { + options.failureDrawableId = failureDrawableId; + return this; + } + + public Builder setFailureDrawable(Drawable failureDrawable) { + options.failureDrawable = failureDrawable; + return this; + } + + public Builder setFadeIn(boolean fadeIn) { + options.fadeIn = fadeIn; + return this; + } + + public Builder setAnimation(Animation animation) { + options.animation = animation; + return this; + } + + public Builder setPlaceholderScaleType(ImageView.ScaleType placeholderScaleType) { + options.placeholderScaleType = placeholderScaleType; + return this; + } + + public Builder setImageScaleType(ImageView.ScaleType imageScaleType) { + options.imageScaleType = imageScaleType; + return this; + } + + public Builder setForceLoadingDrawable(boolean forceLoadingDrawable) { + options.forceLoadingDrawable = forceLoadingDrawable; + return this; + } + + public Builder setUseMemCache(boolean useMemCache) { + options.useMemCache = useMemCache; + return this; + } + + public Builder setParamsBuilder(ParamsBuilder paramsBuilder) { + options.paramsBuilder = paramsBuilder; + return this; + } + } + +} diff --git a/app/src/main/java/org/xutils/image/MemCacheKey.java b/app/src/main/java/org/xutils/image/MemCacheKey.java new file mode 100644 index 0000000..a41296f --- /dev/null +++ b/app/src/main/java/org/xutils/image/MemCacheKey.java @@ -0,0 +1,38 @@ +package org.xutils.image; + +/** + * Created by wyouflf on 15/10/20. + */ +/*package*/ final class MemCacheKey { + public final String url; + public final ImageOptions options; + + public MemCacheKey(String url, ImageOptions options) { + this.url = url; + this.options = options; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MemCacheKey that = (MemCacheKey) o; + + if (!url.equals(that.url)) return false; + return options.equals(that.options); + + } + + @Override + public int hashCode() { + int result = url.hashCode(); + result = 31 * result + options.hashCode(); + return result; + } + + @Override + public String toString() { + return url + options.toString(); + } +} diff --git a/app/src/main/java/org/xutils/image/ReusableBitmapDrawable.java b/app/src/main/java/org/xutils/image/ReusableBitmapDrawable.java new file mode 100644 index 0000000..0d46320 --- /dev/null +++ b/app/src/main/java/org/xutils/image/ReusableBitmapDrawable.java @@ -0,0 +1,24 @@ +package org.xutils.image; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; + +/*package*/ final class ReusableBitmapDrawable extends BitmapDrawable implements ReusableDrawable { + + private MemCacheKey key; + + public ReusableBitmapDrawable(Resources res, Bitmap bitmap) { + super(res, bitmap); + } + + @Override + public MemCacheKey getMemCacheKey() { + return key; + } + + @Override + public void setMemCacheKey(MemCacheKey key) { + this.key = key; + } +} diff --git a/app/src/main/java/org/xutils/image/ReusableDrawable.java b/app/src/main/java/org/xutils/image/ReusableDrawable.java new file mode 100644 index 0000000..5fc9d56 --- /dev/null +++ b/app/src/main/java/org/xutils/image/ReusableDrawable.java @@ -0,0 +1,12 @@ +package org.xutils.image; + +/** + * Created by wyouflf on 15/10/20. + * 使已被LruCache移除, 但还在被ImageView使用的Drawable可以再次被回收使用. + */ +/*package*/ interface ReusableDrawable { + + MemCacheKey getMemCacheKey(); + + void setMemCacheKey(MemCacheKey key); +} diff --git a/app/src/main/java/org/xutils/view/EventListenerManager.java b/app/src/main/java/org/xutils/view/EventListenerManager.java new file mode 100644 index 0000000..5213371 --- /dev/null +++ b/app/src/main/java/org/xutils/view/EventListenerManager.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.view; + +import android.text.TextUtils; +import android.view.View; + +import org.xutils.common.util.DoubleKeyValueMap; +import org.xutils.common.util.LogUtil; +import org.xutils.view.annotation.Event; + +import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/*package*/ final class EventListenerManager { + + private final static long QUICK_EVENT_TIME_SPAN = 300; + private final static HashSet AVOID_QUICK_EVENT_SET = new HashSet(2); + + static { + AVOID_QUICK_EVENT_SET.add("onClick"); + AVOID_QUICK_EVENT_SET.add("onItemClick"); + } + + private EventListenerManager() { + } + + /** + * k1: viewInjectInfo + * k2: interface Type + * value: listener + */ + private final static DoubleKeyValueMap, Object> + listenerCache = new DoubleKeyValueMap, Object>(); + + + public static void addEventMethod( + //根据页面或view holder生成的ViewFinder + ViewFinder finder, + //根据当前注解ID生成的ViewInfo + ViewInfo info, + //注解对象 + Event event, + //页面或view holder对象 + Object handler, + //当前注解方法 + Method method) { + try { + View view = finder.findViewByInfo(info); + + if (view != null) { + // 注解中定义的接口,比如Event注解默认的接口为View.OnClickListener + Class listenerType = event.type(); + // 默认为空,注解接口对应的Set方法,比如setOnClickListener方法 + String listenerSetter = event.setter(); + if (TextUtils.isEmpty(listenerSetter)) { + listenerSetter = "set" + listenerType.getSimpleName(); + } + + + String methodName = event.method(); + + boolean addNewMethod = false; + /* + 根据View的ID和当前的接口类型获取已经缓存的接口实例对象, + 比如根据View.id和View.OnClickListener.class两个键获取这个View的OnClickListener对象 + */ + Object listener = listenerCache.get(info, listenerType); + DynamicHandler dynamicHandler = null; + /* + 如果接口实例对象不为空 + 获取接口对象对应的动态代理对象 + 如果动态代理对象的handler和当前handler相同 + 则为动态代理对象添加代理方法 + */ + if (listener != null) { + dynamicHandler = (DynamicHandler) Proxy.getInvocationHandler(listener); + addNewMethod = handler.equals(dynamicHandler.getHandler()); + if (addNewMethod) { + dynamicHandler.addMethod(methodName, method); + } + } + + // 如果还没有注册此代理 + if (!addNewMethod) { + + dynamicHandler = new DynamicHandler(handler); + + dynamicHandler.addMethod(methodName, method); + + // 生成的代理对象实例,比如View.OnClickListener的实例对象 + listener = Proxy.newProxyInstance( + listenerType.getClassLoader(), + new Class[]{listenerType}, + dynamicHandler); + + listenerCache.put(info, listenerType, listener); + } + + Method setEventListenerMethod = view.getClass().getMethod(listenerSetter, listenerType); + setEventListenerMethod.invoke(view, listener); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + + public static class DynamicHandler implements InvocationHandler { + // 存放代理对象,比如Fragment或view holder + private WeakReference handlerRef; + // 存放代理方法 + private final HashMap methodMap = new HashMap(1); + + private static long lastClickTime = 0; + + public DynamicHandler(Object handler) { + this.handlerRef = new WeakReference(handler); + } + + public void addMethod(String name, Method method) { + methodMap.put(name, method); + } + + public Object getHandler() { + return handlerRef.get(); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Object handler = handlerRef.get(); + if (handler != null) { + + String eventMethod = method.getName(); + if ("toString".equals(eventMethod)) { + return DynamicHandler.class.getSimpleName(); + } + + method = methodMap.get(eventMethod); + if (method == null && methodMap.size() == 1) { + for (Map.Entry entry : methodMap.entrySet()) { + if (TextUtils.isEmpty(entry.getKey())) { + method = entry.getValue(); + } + break; + } + } + + if (method != null) { + + if (AVOID_QUICK_EVENT_SET.contains(eventMethod)) { + long timeSpan = System.currentTimeMillis() - lastClickTime; + if (timeSpan > 0 && timeSpan < QUICK_EVENT_TIME_SPAN) { + LogUtil.d("onClick cancelled: " + timeSpan); + return null; + } + lastClickTime = System.currentTimeMillis(); + } + + try { + return method.invoke(handler, args); + } catch (Throwable ex) { + throw new RuntimeException("invoke method error:" + + handler.getClass().getName() + "#" + method.getName(), ex); + } + } else { + LogUtil.w("method not impl: " + eventMethod + "(" + handler.getClass().getSimpleName() + ")"); + } + } + return null; + } + } +} diff --git a/app/src/main/java/org/xutils/view/ViewFinder.java b/app/src/main/java/org/xutils/view/ViewFinder.java new file mode 100644 index 0000000..8881c81 --- /dev/null +++ b/app/src/main/java/org/xutils/view/ViewFinder.java @@ -0,0 +1,48 @@ +package org.xutils.view; + +import android.app.Activity; +import android.view.View; + +/** + * Author: wyouflf + * Date: 13-9-9 + * Time: 下午12:29 + */ +/*package*/ final class ViewFinder { + + private View view; + private Activity activity; + + public ViewFinder(View view) { + this.view = view; + } + + public ViewFinder(Activity activity) { + this.activity = activity; + } + + public View findViewById(int id) { + if (view != null) return view.findViewById(id); + if (activity != null) return activity.findViewById(id); + return null; + } + + public View findViewByInfo(ViewInfo info) { + return findViewById(info.value, info.parentId); + } + + public View findViewById(int id, int pid) { + View pView = null; + if (pid > 0) { + pView = this.findViewById(pid); + } + + View view = null; + if (pView != null) { + view = pView.findViewById(id); + } else { + view = this.findViewById(id); + } + return view; + } +} diff --git a/app/src/main/java/org/xutils/view/ViewInfo.java b/app/src/main/java/org/xutils/view/ViewInfo.java new file mode 100644 index 0000000..9c1477a --- /dev/null +++ b/app/src/main/java/org/xutils/view/ViewInfo.java @@ -0,0 +1,30 @@ +package org.xutils.view; + +/** + * Author: wyouflf + * Date: 13-12-5 + * Time: 下午11:25 + */ +/*package*/ final class ViewInfo { + public int value; + public int parentId; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ViewInfo viewInfo = (ViewInfo) o; + + if (value != viewInfo.value) return false; + return parentId == viewInfo.parentId; + + } + + @Override + public int hashCode() { + int result = value; + result = 31 * result + parentId; + return result; + } +} diff --git a/app/src/main/java/org/xutils/view/ViewInjectorImpl.java b/app/src/main/java/org/xutils/view/ViewInjectorImpl.java new file mode 100644 index 0000000..2ddb413 --- /dev/null +++ b/app/src/main/java/org/xutils/view/ViewInjectorImpl.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.view; + +import android.app.Activity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.xutils.ViewInjector; +import org.xutils.common.util.LogUtil; +import org.xutils.view.annotation.ContentView; +import org.xutils.view.annotation.Event; +import org.xutils.view.annotation.ViewInject; +import org.xutils.x; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashSet; + +public final class ViewInjectorImpl implements ViewInjector { + + private static final HashSet> IGNORED = new HashSet>(); + + static { + IGNORED.add(Object.class); + IGNORED.add(Activity.class); + IGNORED.add(android.app.Fragment.class); + try { + IGNORED.add(Class.forName("android.support.v4.app.Fragment")); + IGNORED.add(Class.forName("android.support.v4.app.FragmentActivity")); + } catch (Throwable ignored) { + } + } + + private static final Object lock = new Object(); + private static volatile ViewInjectorImpl instance; + + private ViewInjectorImpl() { + } + + public static void registerInstance() { + if (instance == null) { + synchronized (lock) { + if (instance == null) { + instance = new ViewInjectorImpl(); + } + } + } + x.Ext.setViewInjector(instance); + } + + @Override + public void inject(View view) { + injectObject(view, view.getClass(), new ViewFinder(view)); + } + + @Override + public void inject(Activity activity) { + //获取Activity的ContentView的注解 + Class handlerType = activity.getClass(); + try { + ContentView contentView = findContentView(handlerType); + if (contentView != null) { + int viewId = contentView.value(); + if (viewId > 0) { + activity.setContentView(viewId); + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + injectObject(activity, handlerType, new ViewFinder(activity)); + } + + @Override + public void inject(Object handler, View view) { + injectObject(handler, handler.getClass(), new ViewFinder(view)); + } + + @Override + public View inject(Object fragment, LayoutInflater inflater, ViewGroup container) { + // inject ContentView + View view = null; + Class handlerType = fragment.getClass(); + try { + ContentView contentView = findContentView(handlerType); + if (contentView != null) { + int viewId = contentView.value(); + if (viewId > 0) { + view = inflater.inflate(viewId, container, false); + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + + // inject res & event + injectObject(fragment, handlerType, new ViewFinder(view)); + + return view; + } + + /** + * 从父类获取注解View + */ + private static ContentView findContentView(Class thisCls) { + if (thisCls == null || IGNORED.contains(thisCls) || thisCls.getName().startsWith("androidx.")) { + return null; + } + ContentView contentView = thisCls.getAnnotation(ContentView.class); + if (contentView == null) { + return findContentView(thisCls.getSuperclass()); + } + return contentView; + } + + @SuppressWarnings("ConstantConditions") + private static void injectObject(Object handler, Class handlerType, ViewFinder finder) { + + if (handlerType == null || IGNORED.contains(handlerType) || handlerType.getName().startsWith("androidx.")) { + return; + } + + // 从父类到子类递归 + injectObject(handler, handlerType.getSuperclass(), finder); + + // inject view + Field[] fields = handlerType.getDeclaredFields(); + if (fields != null && fields.length > 0) { + for (Field field : fields) { + + Class fieldType = field.getType(); + if ( + /* 不注入静态字段 */ Modifier.isStatic(field.getModifiers()) || + /* 不注入final字段 */ Modifier.isFinal(field.getModifiers()) || + /* 不注入基本类型字段 */ fieldType.isPrimitive() || + /* 不注入数组类型字段 */ fieldType.isArray()) { + continue; + } + + ViewInject viewInject = field.getAnnotation(ViewInject.class); + if (viewInject != null) { + try { + View view = finder.findViewById(viewInject.value(), viewInject.parentId()); + if (view != null) { + field.setAccessible(true); + field.set(handler, view); + } else { + throw new RuntimeException("Invalid @ViewInject for " + + handlerType.getSimpleName() + "." + field.getName()); + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } // end inject view + + // inject event + Method[] methods = handlerType.getDeclaredMethods(); + if (methods != null && methods.length > 0) { + for (Method method : methods) { + + if (Modifier.isStatic(method.getModifiers()) + || !Modifier.isPrivate(method.getModifiers())) { + continue; + } + + //检查当前方法是否是event注解的方法 + Event event = method.getAnnotation(Event.class); + if (event != null) { + try { + // id参数 + int[] values = event.value(); + int[] parentIds = event.parentId(); + int parentIdsLen = parentIds == null ? 0 : parentIds.length; + //循环所有id,生成ViewInfo并添加代理反射 + for (int i = 0; i < values.length; i++) { + int value = values[i]; + if (value > 0) { + ViewInfo info = new ViewInfo(); + info.value = value; + info.parentId = parentIdsLen > i ? parentIds[i] : 0; + method.setAccessible(true); + EventListenerManager.addEventMethod(finder, info, event, handler, method); + } + } + } catch (Throwable ex) { + LogUtil.e(ex.getMessage(), ex); + } + } + } + } // end inject event + + } + +} diff --git a/app/src/main/java/org/xutils/view/annotation/ContentView.java b/app/src/main/java/org/xutils/view/annotation/ContentView.java new file mode 100644 index 0000000..7422694 --- /dev/null +++ b/app/src/main/java/org/xutils/view/annotation/ContentView.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.view.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ContentView { + int value(); +} diff --git a/app/src/main/java/org/xutils/view/annotation/Event.java b/app/src/main/java/org/xutils/view/annotation/Event.java new file mode 100644 index 0000000..3fe4db1 --- /dev/null +++ b/app/src/main/java/org/xutils/view/annotation/Event.java @@ -0,0 +1,48 @@ +package org.xutils.view.annotation; + +import android.view.View; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 事件注解. + * 被注解的方法必须具备以下形式: + * 1. private 修饰 + * 2. 返回值类型没有要求 + * 3. 参数签名和type的接口要求的参数签名一致. + * Author: wyouflf + * Date: 13-9-9 + * Time: 下午12:43 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Event { + + /** + * 控件的id集合, id小于1时不执行ui事件绑定. + */ + int[] value(); + + /** + * 控件的parent控件的id集合, 组合为(value[i], parentId[i] or 0). + */ + int[] parentId() default 0; + + /** + * 事件的listener, 默认为点击事件. + */ + Class type() default View.OnClickListener.class; + + /** + * 事件的setter方法名, 默认为set+type#simpleName. + */ + String setter() default ""; + + /** + * 如果type的接口类型提供多个方法, 需要使用此参数指定方法名. + */ + String method() default ""; +} diff --git a/app/src/main/java/org/xutils/view/annotation/ViewInject.java b/app/src/main/java/org/xutils/view/annotation/ViewInject.java new file mode 100644 index 0000000..95b8043 --- /dev/null +++ b/app/src/main/java/org/xutils/view/annotation/ViewInject.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013. wyouflf (wyouflf@gmail.com) + * + * 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 org.xutils.view.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ViewInject { + + int value(); + + /* parent view id */ + int parentId() default 0; +} diff --git a/app/src/main/java/org/xutils/x.java b/app/src/main/java/org/xutils/x.java new file mode 100644 index 0000000..57cfcc9 --- /dev/null +++ b/app/src/main/java/org/xutils/x.java @@ -0,0 +1,131 @@ +package org.xutils; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; + +import org.xutils.common.TaskController; +import org.xutils.common.task.TaskControllerImpl; +import org.xutils.db.DbManagerImpl; +import org.xutils.ex.DbException; +import org.xutils.http.HttpManagerImpl; +import org.xutils.image.ImageManagerImpl; +import org.xutils.view.ViewInjectorImpl; + +import java.lang.reflect.Method; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; + + +/** + * Created by wyouflf on 15/6/10. + * 任务控制中心, http, image, db, view注入等接口的入口. + * 需要在在application的onCreate中初始化: x.Ext.init(this); + */ +public final class x { + + private x() { + } + + public static boolean isDebug() { + return Ext.debug; + } + + public static Application app() { + if (Ext.app == null) { + try { + // 仅在IDE进行布局预览时使用,真机或模拟器不使用MockApplication. + @SuppressLint("PrivateApi") + Class renderActionClass = Class.forName("com.android.layoutlib.bridge.impl.RenderAction"); + Method method = renderActionClass.getDeclaredMethod("getCurrentContext"); + Context context = (Context) method.invoke(null); + Ext.app = new MockApplication(context); + } catch (Throwable ignored) { + throw new RuntimeException("please invoke x.Ext.init(app) on Application#onCreate()" + + " and register your Application in manifest."); + } + } + return Ext.app; + } + + public static TaskController task() { + return Ext.taskController; + } + + public static HttpManager http() { + if (Ext.httpManager == null) { + HttpManagerImpl.registerInstance(); + } + return Ext.httpManager; + } + + public static ImageManager image() { + if (Ext.imageManager == null) { + ImageManagerImpl.registerInstance(); + } + return Ext.imageManager; + } + + public static ViewInjector view() { + if (Ext.viewInjector == null) { + ViewInjectorImpl.registerInstance(); + } + return Ext.viewInjector; + } + + public static DbManager getDb(DbManager.DaoConfig daoConfig) throws DbException { + return DbManagerImpl.getInstance(daoConfig); + } + + public static class Ext { + private static boolean debug; + private static Application app; + private static TaskController taskController; + private static HttpManager httpManager; + private static ImageManager imageManager; + private static ViewInjector viewInjector; + + private Ext() { + } + + public static void init(Application app) { + TaskControllerImpl.registerInstance(); + if (Ext.app == null) { + Ext.app = app; + } + } + + public static void setDebug(boolean debug) { + Ext.debug = debug; + } + + public static void setTaskController(TaskController taskController) { + if (Ext.taskController == null) { + Ext.taskController = taskController; + } + } + + public static void setHttpManager(HttpManager httpManager) { + Ext.httpManager = httpManager; + } + + public static void setImageManager(ImageManager imageManager) { + Ext.imageManager = imageManager; + } + + public static void setViewInjector(ViewInjector viewInjector) { + Ext.viewInjector = viewInjector; + } + + public static void setDefaultHostnameVerifier(HostnameVerifier hostnameVerifier) { + HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); + } + } + + private static class MockApplication extends Application { + public MockApplication(Context baseContext) { + this.attachBaseContext(baseContext); + } + } +} diff --git a/app/src/main/res/drawable-nodpi/back.png b/app/src/main/res/drawable-nodpi/back.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff36df29f398793e07891fe9ff1e9d93d0e5344 GIT binary patch literal 695 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 z�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 AD*ylh literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/bg_main.png b/app/src/main/res/drawable-nodpi/bg_main.png new file mode 100644 index 0000000000000000000000000000000000000000..d81134b8b92ebc431e36691951d122d7cc0ccfce GIT binary patch literal 47887 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�lBO~U7v`3Zk%$ChnV$LMxoM0@5g%ubPWyG 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

bdOajiPt_tQG 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 KcdKtdef59!`v&{~ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/cancel.png b/app/src/main/res/drawable-nodpi/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..476a30cde31f38adeccbfbf545652b665b394f99 GIT binary patch literal 419 zcmV;U0bKrxP)Px$T}ebiR7gwBmO)O#Fc3xmSlMs@))axn9asTk%SocdIZC7`H(`l@RZjs;ShI&s zaHxy785*0QOt}n&qQ<%;G4A8?3~+n zU3XL0^~XM}G)>QvBzXle>(8M)&lf9d|86hX5X7oQLmvRNM07h=Mk^OHzqpy$v#d&F z(~uU#$`}fG36fwjnRx#F8Q@tPo_O_Db(k=9mX+)49qbq+@fd@f-X2zH&BD!!1%>1sDx{oRB{{!+^cv|T^ z7M|7&QpNl1Ep?E;E7&m=|LYbsW@D)9Z_9YdYhvT_T!La-y);LJ&N$vxuC-nOup`mI zh7$nI&bSro!ZBmmkaI2QXanRGGhZ|FV^vk3F%ieE$+GMezymYSe*hI#jmX&p^O^tv N002ovPDHLkV1kavw*>$I literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/check.png b/app/src/main/res/drawable-nodpi/check.png new file mode 100644 index 0000000000000000000000000000000000000000..a08bdb61cb92c4f79e68ebfe1e54b5d2bcae4206 GIT binary patch literal 3785 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 T5vwy000000NkvXXu0mjf*QpH@ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/date.png b/app/src/main/res/drawable-nodpi/date.png new file mode 100644 index 0000000000000000000000000000000000000000..bc3b23b4e4f975b063b6daaa7d35c33ee1832d99 GIT binary patch literal 993 zcmV<710MW|P)Px&n@L1LR9Hvtn9XlZQ4qjq&b`XYLy3=wMA9Gxxo4inPONNfBw|SNj=rxdxmN6tEb+5@2LAqr6+kwn>%ObcV_0y zIcE^2$iOMW3Dcl?M`}VIC8A}_{0IO_!^6XCdwY97xPWP`4>Xi z6buawE$!~^e&I6D36zKy$8oI63Vq+Vh1+5@84rO%68)KUPNl+qMtCZ?-29?ueU|?Wo ze}BJtc+y5|YwHSTe(DS=8W6;P zTv*$X8>s7v^P{BZzP$RNvg@t2`GOhM}NCKO@r3Sk!g?SwTa4la`R{q1nZSj7ylFx5x;t# zx4XT){dJ|T+(3y)j?TiLg35emei(+~rbdCbBVw!Tsa0!1aU5TXqUbnb*DguCAU0q$btAeKGr%frfv4J=Dn(GuuYwf)-47ZjA zGrL(tqnJsq#3rRLGup6l=0{{_X;mb`TjH^ P00000NkvXXu0mjf^4{A( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/device.png b/app/src/main/res/drawable-nodpi/device.png new file mode 100644 index 0000000000000000000000000000000000000000..78f8174ef1a13c25e8759e9ef8cdf597a8f69adc GIT binary patch literal 2954 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 E0FCZbC;$Ke literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/info.png b/app/src/main/res/drawable-nodpi/info.png new file mode 100644 index 0000000000000000000000000000000000000000..2220fe6496b3874d1335584a6fa59e52dd9ffcf0 GIT binary patch literal 4632 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

7>#6wP$SyQm`9N_ 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

EWv-{}u8+EOk1;Hc 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/logo.png b/app/src/main/res/drawable-nodpi/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..de4102afad8723ac4d053a0a4a075aac434da9ec GIT binary patch literal 99105 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
  • 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 LNkvXXu0mjfZv>7h literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/minus.png b/app/src/main/res/drawable-nodpi/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..3530d92cca2dd3090bc9b45769e8afe7a2f7c1f7 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|NrIOa6O^sms>Yi h(?TmL7iEPG1~XkP$*XRf*MJUS@O1TaS?83{1OR#8Kg|FD literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/multi.png b/app/src/main/res/drawable-nodpi/multi.png new file mode 100644 index 0000000000000000000000000000000000000000..8f95f5b3bf07f5f99131067b86810c787fa5bc63 GIT binary patch literal 348 zcmV-i0i*tjP)Px$7D+@wR7gw3RZD8aFch383MCsaV<_q&EN_w<!8_#U!6jnIg%Do=k`Dh@ z*L7ldGVVYqrGAO%$*N*jWQH8fd@RfI*|v6K(cD1*1CbC+U*K$td<5p;$QJX;X{9r! zE|IRX-g7Ux`RJVkhlm{#ZwM9z48S9@NWQ*6REwhi_dxU1qn umK~z5>wZL|UO0g_STJmzJ2|+#0N@oG&GZ?<)zj$!0000my=%r literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/next.png b/app/src/main/res/drawable-nodpi/next.png new file mode 100644 index 0000000000000000000000000000000000000000..bd76583b7f7364fbdc9ce1ba0cb666394819bd60 GIT binary patch literal 446 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 bHlY6iT(uEN>K7k500000NkvXXu0mjf7sawU literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/tips.png b/app/src/main/res/drawable-nodpi/tips.png new file mode 100644 index 0000000000000000000000000000000000000000..724639746c1b08f0a38fe39298ba129d75538237 GIT binary patch literal 2812 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 T>TQGX00000NkvXXu0mjftnO`u literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..696a842 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + 智慧蚕桑Compose版 + Show less + Show more + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..a401920 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml new file mode 100644 index 0000000..a282c50 --- /dev/null +++ b/app/src/main/res/xml/provider_paths.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/test/java/com/bbit/silk/ExampleUnitTest.kt b/app/src/test/java/com/bbit/silk/ExampleUnitTest.kt new file mode 100644 index 0000000..eb882b8 --- /dev/null +++ b/app/src/test/java/com/bbit/silk/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.bbit.silk + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..664ab6a --- /dev/null +++ b/build.gradle @@ -0,0 +1,5 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { +alias(libs.plugins.androidApplication) apply false + alias(libs.plugins.jetbrainsKotlinAndroid) apply false +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..3d2bd1c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,5 @@ +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +android.useAndroidX=true +kotlin.code.style=official +android.nonTransitiveRClass=true +android.enableJetifier=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..2e77781 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,53 @@ +[versions] +agp = "8.7.0-alpha02" +androidPickerview = "4.1.9" +androidxLegacyLegacySupportV4 = "1.0.0" +blankjUtilcodexVersion = "1.31.1" +composeviewsVersion = "1.6.0.1" +googleGsonVersion = "2.10.1" +githubXxpermissionsVersion = "18.5" +kotlin = "1.9.20" +coreKtx = "1.12.0" +junit = "4.13.2" +junitVersion = "1.1.5" +espressoCore = "3.5.1" +lifecycleRuntimeKtx = "2.6.2" +activityCompose = "1.8.0" +composeBom = "2023.10.01" +coreSplashscreen = "1.0.1" +mmkv = "1.2.13" +timber = "5.0.1" +navigationCompose = "2.7.7" + +[libraries] +android-pickerview = { module = "com.contrarywind:Android-PickerView", version.ref = "androidPickerview" } +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-legacy-legacy-support-v43 = { module = "androidx.legacy:legacy-support-v4", version.ref = "androidxLegacyLegacySupportV4" } +androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" } +androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" } +androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } +com-github-getactivity-xxpermissions = { module = "com.github.getActivity:XXPermissions", version.ref = "githubXxpermissionsVersion" } +com-google-code-gson-gson2 = { module = "com.google.code.gson:gson", version.ref = "googleGsonVersion" } +com-blankj-utilcodex2 = { module = "com.blankj:utilcodex", version.ref = "blankjUtilcodexVersion" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "coreSplashscreen" } +ltttttttttttt-composeviews = { module = "io.github.ltttttttttttt:ComposeViews", version.ref = "composeviewsVersion" } +mmkv = { module = "com.tencent:mmkv", version.ref = "mmkv" } +timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } + +[plugins] +androidApplication = { id = "com.android.application", version.ref = "agp" } +jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

    K7UpUK$>l@ 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 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..1d73478 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Apr 29 17:07:43 CST 2024 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# 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 + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# 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 +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +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" -a "$nonstop" = "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 or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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 + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@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 + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@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="-Xmx64m" "-Xms64m" + +@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 execute + +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 execute + +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 + +: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 %* + +: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/key/keystore.jks b/key/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..55ec5d9441c7c72cfe1302ee5092efa3688d0e63 GIT binary patch literal 2500 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 literal 0 HcmV?d00001 diff --git a/local.properties b/local.properties new file mode 100644 index 0000000..8a0e424 --- /dev/null +++ b/local.properties @@ -0,0 +1,8 @@ +## This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Wed Oct 30 16:11:52 CST 2024 +sdk.dir=C\:\\Users\\BBIT\\AppData\\Local\\Android\\Sdk diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..0477382 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,25 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + jcenter() // Warning: this repository is going to shut down soon + maven { url 'https://jitpack.io' } + } +} + +rootProject.name = "silk" +include ':app'