diff --git a/README_CN.md b/README_CN.md index 848897fe4ef002fa73e214020de4853c1e9c7339..4985356c617156d90b1ec6e040059a41c0dcb3dd 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,4 +1,7 @@ -# **在线体验暂时下线 !!!** +2024-04-11 升级到SpringBoot3.0.2 + +# **在线体验暂时下线** + ####   在线文档:[https://ajcaptcha.beliefteam.cn/captcha-doc/](https://ajcaptcha.beliefteam.cn/captcha-doc/ "doc")
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)[![Total Lines](https://tokei.rs/b1/github/anji-plus/captcha?category=lines)](https://github.com/anji-plus/captcha) @@ -76,13 +79,20 @@ I Your application is running here: http://localhost:8081  详细的前后端接入文档,后端示例代码service目录下,前端示例代码view目录下。 -# 6 技术支持,如有问题,请提交Issue -加微信前请备注AJ-Captcha。 -
微信群地址 +# 6 技术支持,如有问题,请提交[Issue](https://gitee.com/anji-plus/captcha/issues) + +AJ-Captcha技术支持三群,有问题都可以在群里问
+如果不能直接加进去或者群二维码过期了,请添加下面个人微信
+
+ + +个人微信:个人微信,不闲聊,加群、咨询请备注,备注格式不限但最好是:“项目名 + 问题”, 项目名可以是**AJ-Captcha**、**Captcha**、**验证码**,只要能一眼分辨就行
+例1:验证码 加群
+例2:captche 有个问题xxxx
+有问题,不管是技术问题还是使用问题,都尽量在群里问,没啥特殊问题尽量别加个人微信。加个人微信记得**一定要加备注 !!!**
+ + -| 微信 | qq | -| --- | --- | -||| #### 开源不易,劳烦各位star ☺ @@ -92,5 +102,8 @@ I Your application is running here: http://localhost:8081
-# Stargazers over time + + +## Stargazers over time + [![Stargazers over time](https://starchart.cc/anji-plus/captcha.svg)](https://starchart.cc/anji-plus/captcha) diff --git a/core/captcha-spring-boot-starter/pom.xml b/core/captcha-spring-boot-starter/pom.xml index f0c417818c0371bd1523ad6a3604e9dd6b917a83..95b65d9689ea56c300f775e7a3361962d991764b 100644 --- a/core/captcha-spring-boot-starter/pom.xml +++ b/core/captcha-spring-boot-starter/pom.xml @@ -7,7 +7,7 @@ org.springframework.boot spring-boot-starter-parent - 2.3.5.RELEASE + 3.0.2 com.anji-plus @@ -20,8 +20,8 @@ jar - 1.8 - 2.3.5.RELEASE + 17 + 3.0.2 @@ -85,8 +85,8 @@ maven-compiler-plugin 3.3 - 1.8 - 1.8 + 17 + 17 UTF-8 diff --git a/core/captcha-spring-boot-starter/src/main/java/com/anji/captcha/controller/CaptchaController.java b/core/captcha-spring-boot-starter/src/main/java/com/anji/captcha/controller/CaptchaController.java index 468833ecd3091e6dc0807b9040dec3a579f6a4ef..8156e0fb9d284749002c306e80ca29de08af2df7 100644 --- a/core/captcha-spring-boot-starter/src/main/java/com/anji/captcha/controller/CaptchaController.java +++ b/core/captcha-spring-boot-starter/src/main/java/com/anji/captcha/controller/CaptchaController.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; @RestController diff --git a/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring.factories b/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 218ca002bbfb20df68c06df396b1135f997077e7..0000000000000000000000000000000000000000 --- a/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.anji.captcha.config.AjCaptchaAutoConfiguration \ No newline at end of file diff --git a/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000000000000000000000000000000000..4a295be86e25d9c5546ea2d19388f836d9e1a1ba --- /dev/null +++ b/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.anji.captcha.config.AjCaptchaAutoConfiguration diff --git a/core/captcha/pom.xml b/core/captcha/pom.xml index c9585dc9cef984bc09d9f75bff72ce2f47ac42ab..8394cd59ff0246db10d9b3d16f66c93fdbc91c48 100644 --- a/core/captcha/pom.xml +++ b/core/captcha/pom.xml @@ -16,7 +16,7 @@ UTF-8 UTF-8 - 1.8 + 17 @@ -24,7 +24,7 @@ org.slf4j slf4j-api - 1.7.25 + 2.0.2 provided @@ -51,7 +51,6 @@ https://github.com/anji-plus - snapshots @@ -65,8 +64,8 @@ maven-compiler-plugin 3.3 - 1.8 - 1.8 + 17 + 17 UTF-8 diff --git "a/images/\346\273\221\345\212\250\346\213\274\345\233\276.gif" "b/images/\346\273\221\345\212\250\346\213\274\345\233\276.gif" new file mode 100644 index 0000000000000000000000000000000000000000..0f170423bc1aa339e1d79e50aaf508b02db339a0 Binary files /dev/null and "b/images/\346\273\221\345\212\250\346\213\274\345\233\276.gif" differ diff --git "a/images/\347\202\271\351\200\211\346\226\207\345\255\227.gif" "b/images/\347\202\271\351\200\211\346\226\207\345\255\227.gif" new file mode 100644 index 0000000000000000000000000000000000000000..0910b153794ce25e5a1638fe2d1b9c5a4774222f Binary files /dev/null and "b/images/\347\202\271\351\200\211\346\226\207\345\255\227.gif" differ diff --git a/pom.xml b/pom.xml index ac7634024984c73afaf739069040fd8a0b2fea68..97c7f587ddf93d450488352a6b5b592fdf5fc204 100644 --- a/pom.xml +++ b/pom.xml @@ -10,10 +10,10 @@ pom - 2.0.4.RELEASE + 3.0.2 1.2.0 - 1.8 - 1.8 + 17 + 17 UTF-8 @@ -43,6 +43,18 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + core/captcha core/captcha-spring-boot-starter diff --git a/service/php/readme.md b/service/php/readme.md index 1c9a8256aaae5628135be4e623320408ce25927f..bd122260834865c2d17125776e820800431097b9 100644 --- a/service/php/readme.md +++ b/service/php/readme.md @@ -27,6 +27,12 @@ test 目录下示例了三种使用方式,phper可以参考使用。[查看dem 2. 基于框架使用的场景,输入安装命令`composer require fastknife/ajcaptcha`(稳定版) 或者`composer require fastknife/ajcaptcha dev-master`(最新版) ,建议使用composer阿里源(`https://mirrors.aliyun.com/composer`) * 支持各种前沿框架(ThinkPHP, YII, Laravel, Hyperf,IMI,Swoft,EasySwoole) * 本软件包内,未使用单例、注册树(容器)模式,不含任何全局变量,基于swoole开发的同学不用担心内存泄露。 + +3. 以thinkphp框架后端和vue框架前端为例,在本地开发环境运行起示例项目说明: +3.1 开启命令行窗口,进入 captcha\service\php\test\thinkphp 目录,执行 `composer install` 命令安装依赖,执行 `php think run` 命令启动接口服务。 +3.2 修改 captcha\view\vue\config\dev.env.js 中 BASE_API: '"http://localhost:8000"' ,取值与 3.1中启动的接口服务地址一致。 +3.3 开启命令行窗口,进入 captcha\view\vue 目录,执行 `npm install` 命令安装依赖,执行 `npm run dev` 命令启动前端项目。 + #### 项目结构 > 本软件包基于整洁架构理念,设计了下文的目录结构。Domain(领域层)作为内层同心圆承担所有业务逻辑功能,Service(服务层)并向最外层Controller(需自行实现)提供粗颗粒度服务。 diff --git a/service/php/test/thinkphp/app/controller/Index.php b/service/php/test/thinkphp/app/controller/Index.php index a773762f25c4d1ab278c8db55213e3936a99c8fd..0494b638391a315120f2c9ef0dd5e9c410f943f6 100644 --- a/service/php/test/thinkphp/app/controller/Index.php +++ b/service/php/test/thinkphp/app/controller/Index.php @@ -21,6 +21,16 @@ class Index } catch (\Exception $e) { $this->error($e->getMessage()); } + /* 如果开发框架开启了debug、trace,导致前端项目无法正确获取到后台接口的返回数据,可以修改为本注释内的接口返回方式 + $response = [ + 'error' => false, + 'repCode' => '0000', + 'repData' => $data, + 'repMsg' => null, + 'success' => true, + ]; + return json($response);*/ + $this->success($data); } @@ -34,6 +44,15 @@ class Index } catch (\Exception $e) { $this->error($e->getMessage()); } + /* 如果开发框架开启了debug、trace,导致前端项目无法正确获取到后台接口的返回数据,可以修改为本注释内的接口返回方式 + $response = [ + 'error' => false, + 'repCode' => '0000', + 'repData' => [], + 'repMsg' => null, + 'success' => true, + ]; + return json($response);*/ $this->success([]); } diff --git a/service/php/test/thinkphp/config/route.php b/service/php/test/thinkphp/config/route.php new file mode 100644 index 0000000000000000000000000000000000000000..955eeec0eb63b906922972d096cc2972839a53b7 --- /dev/null +++ b/service/php/test/thinkphp/config/route.php @@ -0,0 +1,45 @@ + '/', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + // URL普通方式参数 用于自动生成 + 'url_common_param' => true, + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => false, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => false, + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 默认JSONP格式返回的处理方法 + 'default_jsonp_handler' => 'jsonpReturn', + // 默认JSONP处理方法 + 'var_jsonp_handler' => 'callback', +]; diff --git a/service/php/test/thinkphp/route/app.php b/service/php/test/thinkphp/route/app.php new file mode 100644 index 0000000000000000000000000000000000000000..e82de9196b279b0ec13825a919d2725cae1bca51 --- /dev/null +++ b/service/php/test/thinkphp/route/app.php @@ -0,0 +1,18 @@ + +// +---------------------------------------------------------------------- +use think\facade\Route; + +Route::get('think', function () { + return 'hello,ThinkPHP6!'; +}); + +Route::post('/captcha/get', 'Index/index')->allowCrossDomain(); +Route::post('/captcha/check', 'Index/check')->allowCrossDomain(); \ No newline at end of file diff --git a/service/springboot/pom.xml b/service/springboot/pom.xml index 54bd33a21f7e7d301352b4b46e3a00aa3c5a634a..7e83a1c5d7e5baabf44b1214649d7b8ef0f67afa 100644 --- a/service/springboot/pom.xml +++ b/service/springboot/pom.xml @@ -7,7 +7,7 @@ org.springframework.boot spring-boot-starter-parent - 2.3.5.RELEASE + 3.0.2 com.anji.captcha @@ -20,8 +20,8 @@ jar - 1.8 - 2.3.5.RELEASE + 17 + 3.0.2 true @@ -61,6 +61,13 @@ + + + junit + junit + 4.11 + test + @@ -70,6 +77,14 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + diff --git a/service/springboot/src/main/java/com/anji/captcha/demo/filter/CorsFilter.java b/service/springboot/src/main/java/com/anji/captcha/demo/filter/CorsFilter.java index f6840794aae2ea1c5133d2a977f34e9bce684902..ff36e7c48612af0a09ade6e7cd8930514e4a1954 100644 --- a/service/springboot/src/main/java/com/anji/captcha/demo/filter/CorsFilter.java +++ b/service/springboot/src/main/java/com/anji/captcha/demo/filter/CorsFilter.java @@ -12,10 +12,10 @@ package com.anji.captcha.demo.filter; */ import org.springframework.context.annotation.Configuration; -import javax.servlet.*; -import javax.servlet.annotation.WebFilter; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; @WebFilter(filterName = "CorsFilter ") diff --git a/service/springmvc/pom.xml b/service/springmvc/pom.xml index 351af8cd1a446b24d30e43edbd32e7ca6915e778..1963c801d3fcde7be7a5c843e40dee3609d13774 100644 --- a/service/springmvc/pom.xml +++ b/service/springmvc/pom.xml @@ -1,7 +1,7 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.anjiplus.demo @@ -14,12 +14,12 @@ UTF-8 - 1.7 - 1.7 + 17 + 17 1.8 1.6.6 1.2.12 - 5.0.16.RELEASE + 6.0.4 @@ -33,7 +33,7 @@ com.anji-plus captcha - 1.2.9 + 1.3.1 com.alibaba @@ -96,13 +96,13 @@ org.slf4j slf4j-api - 1.7.25 + 2.0.2 org.slf4j slf4j-log4j12 - 1.7.25 + 2.0.2 @@ -114,7 +114,7 @@ org.springframework.data spring-data-redis - 1.8.1.RELEASE + 3.0.1 diff --git a/view/doc/docs/README.md b/view/doc/docs/README.md index 60f5bd760af44dcdfd41111cea1c352fbb2c222d..b2c3e4a38372ad5a3020940b6dcf147f5c74d675 100644 --- a/view/doc/docs/README.md +++ b/view/doc/docs/README.md @@ -1,21 +1,9 @@ -# 在线体验 -####   1.1 电脑在线体验:[https://captcha.anji-plus.com/](https://captcha.anji-plus.com/ "链接") -####   1.2 在线文档:[https://captcha.anji-plus.com/#/doc](https://captcha.anji-plus.com/#/doc "doc")
-####   1.3 微信小程序和H5在线体验(基于uni-app实现) -   如果图片未能正常展示,可查看码云,和github同步 [码云]( https://gitee.com/anji-plus/captcha "码云")
-![微信小程序](https://captcha.anji-plus.com/static/8cm.jpg "微信小程序")  
-    微信小程序Demo             # 功能概述 ####   2.1 组件介绍    行为验证码采用嵌入式集成方式,接入方便,安全,高效。抛弃了传统字符型验证码展示-填写字符-比对答案的流程,采用验证码展示-采集用户行为-分析用户行为流程,用户只需要产生指定的行为轨迹,不需要键盘手动输入,极大优化了传统验证码用户体验不佳的问题;同时,快速、准确的返回人机判定结果。目前对外提供两种类型的验证码,其中包含滑动拼图、文字点选。如图1-1、1-2所示。若希望不影响原UI布局,可采用弹出式交互。
   后端基于Java实现,提供纯Java.jar和SpringBoot Starter。前端提供了Android、iOS、Futter、Uni-App、ReactNative、Vue、Angular、Html、Php等多端示例。
-| 滑动拼图 | 文字点选 | -| --- | --- | -|![滑动拼图](https://captcha.anji-plus.com/static/blockPuzzle.png "滑动拼图") |![点选文字](https://captcha.anji-plus.com/static/clickWord.png "点选文字")| -| 图1-1 | 图1-2 | -
####   2.2 概念术语描述 | 术语 | 描述 | @@ -30,7 +18,7 @@ ③ 用户提交表单,前端将第二步的输出一同提交到后台
④ 验证数据随表单提交到后台后,后台需要调用captchaService.verification做二次校验。
⑤ 第4步返回校验通过/失败到产品应用后端,再返回到前端。如下图所示。 -![时序图](https://captcha.anji-plus.com/static/shixu.png "时序图") + # 目录结构 ├─core
@@ -66,14 +54,6 @@ I Your application is running here: http://localhost:8081  详细的前后端接入文档,后端示例代码service目录下,前端示例代码view目录下。 -# 近期计划 -####   6.1 增加weex示例 -####   6.2 增加ReactNative示例(已添加) - -# 技术支持微信群 -微信一群已满,现开放二群。github可能有缓存,不会自动更新。 -
微信群地址:https://captcha.anji-plus.com/static/weixin.png - #### 开源不易,劳烦各位star ☺ diff --git a/view/flutter/demo/ios/Flutter/AppFrameworkInfo.plist b/view/flutter/demo/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78a7850094f62713858e533a2fc8eda617..f2872cf474eee0cc0439d4012e1a653ac08e9d0f 100644 --- a/view/flutter/demo/ios/Flutter/AppFrameworkInfo.plist +++ b/view/flutter/demo/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 9.0 diff --git a/view/flutter/demo/ios/Runner.xcodeproj/project.pbxproj b/view/flutter/demo/ios/Runner.xcodeproj/project.pbxproj index 3705ccabe4f327442e82a3a73ed94e32f982392c..d63af51b714e5bee96a8e9bdd11641c951c2218b 100644 --- a/view/flutter/demo/ios/Runner.xcodeproj/project.pbxproj +++ b/view/flutter/demo/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -135,7 +135,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -241,7 +241,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -281,7 +280,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -318,7 +317,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -364,7 +362,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -374,7 +372,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -414,7 +411,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/view/flutter/demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/view/flutter/demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16ed0f1cd0c2409d848bf489b93fefa3b2..919434a6254f0e9651f402737811be6634a03e9c 100644 --- a/view/flutter/demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/view/flutter/demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/view/flutter/demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/view/flutter/demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cfdb3ff9b7a11a9497b84546d615db2afa..3db53b6e1fb7f8a5fae6c2e6eb4e3b4382a3691e 100644 --- a/view/flutter/demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/view/flutter/demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone + diff --git a/view/flutter/demo/lib/request/HttpManager.dart b/view/flutter/demo/lib/request/HttpManager.dart index 711b9c6a647344c0b204e459713d256f1fee66c2..80bc84064a7a32ad8cf905db206155c58001d422 100644 --- a/view/flutter/demo/lib/request/HttpManager.dart +++ b/view/flutter/demo/lib/request/HttpManager.dart @@ -14,8 +14,8 @@ class HttpManager { "content-Type": CONTENT_TYPE_JSON }; //请求base url -// static String baseUrl = "http://10.108.11.46:8080/api"; - static String baseUrl = "https://captcha.anji-plus.com/captcha-api"; + static String baseUrl = "http://127.0.0.1:8080"; +// static String baseUrl = "https://captcha.anji-plus.com/captcha-api"; ///发起网络请求 ///[ url] 请求url diff --git a/view/flutter/demo/pubspec.lock b/view/flutter/demo/pubspec.lock index c25ade49779af5381d0ec5283122992a45ca614e..08ee1ce8a409f4f16a8144fd98caa0ba3cd6840d 100644 --- a/view/flutter/demo/pubspec.lock +++ b/view/flutter/demo/pubspec.lock @@ -5,86 +5,100 @@ packages: dependency: transitive description: name: args - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.5.2" + version: "1.6.0" asn1lib: dependency: transitive description: name: asn1lib - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.5.15" + version: "0.6.5" async: dependency: transitive description: name: async - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.8.2" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.3.1" clock: dependency: transitive description: name: clock - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.1.0" collection: dependency: transitive description: name: collection - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.14.11" + version: "1.16.0" convert: dependency: transitive description: name: convert - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.5" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.1.3" dio: dependency: "direct main" description: name: dio - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "3.0.9" + version: "3.0.10" encrypt: dependency: "direct main" description: name: encrypt - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.3" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" flutter: dependency: "direct main" description: flutter @@ -99,51 +113,44 @@ packages: dependency: transitive description: name: http_parser - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.3" + version: "3.1.4" matcher: dependency: transitive description: name: matcher - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" source: hosted - version: "0.12.5" + version: "0.1.4" meta: dependency: transitive description: name: meta - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.7" + version: "1.7.0" path: dependency: transitive description: name: path - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.6.4" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.8.0+1" + version: "1.8.1" pointycastle: dependency: transitive description: name: pointycastle - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.2" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.5" sky_engine: dependency: transitive description: flutter @@ -153,64 +160,64 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.5.5" + version: "1.8.2" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "1.10.0" steel_crypt: dependency: "direct main" description: name: steel_crypt - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.5.4" + version: "1.7.1+1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.2.5" + version: "0.4.9" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.3.1" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.2" sdks: - dart: ">2.4.0 <3.0.0" + dart: ">=2.17.0-0 <3.0.0" diff --git a/view/flutter/demo_null_safety/.gitignore b/view/flutter/demo_null_safety/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..8786b9410f4d39e9c8d0a11f8806a8c31aad3fd4 --- /dev/null +++ b/view/flutter/demo_null_safety/.gitignore @@ -0,0 +1,4 @@ +/.dart_tool/ +/.idea/ +/build/ +.packages \ No newline at end of file diff --git a/view/flutter/demo_null_safety/README.md b/view/flutter/demo_null_safety/README.md new file mode 100644 index 0000000000000000000000000000000000000000..40905729cfcdcd29f5db475b3fee304126a2a387 --- /dev/null +++ b/view/flutter/demo_null_safety/README.md @@ -0,0 +1,16 @@ +# captcha + +A new Flutter application. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/view/flutter/demo_null_safety/android/.gitignore b/view/flutter/demo_null_safety/android/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..bc2100d8f75e6efef413729756e448e910f7304d --- /dev/null +++ b/view/flutter/demo_null_safety/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/view/flutter/demo_null_safety/android/app/build.gradle b/view/flutter/demo_null_safety/android/app/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..acf469b36241a0c0ab5f3ddf16afd7c3a09dc174 --- /dev/null +++ b/view/flutter/demo_null_safety/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.anjiplus.captcha" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + ndk { + abiFilters 'armeabi-v7a','x86' + } + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + + ndk { + abiFilters 'armeabi-v7a' + } + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/view/flutter/demo_null_safety/android/app/src/debug/AndroidManifest.xml b/view/flutter/demo_null_safety/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba4ee87a2fc9f25967ca6df8b1213b93b6fdd881 --- /dev/null +++ b/view/flutter/demo_null_safety/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/view/flutter/demo_null_safety/android/app/src/main/AndroidManifest.xml b/view/flutter/demo_null_safety/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..40685f6690352fb5f55b4edf9d601746d6b49555 --- /dev/null +++ b/view/flutter/demo_null_safety/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/view/flutter/demo_null_safety/android/app/src/main/kotlin/com/anjiplus/captcha/MainActivity.kt b/view/flutter/demo_null_safety/android/app/src/main/kotlin/com/anjiplus/captcha/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..ae94e2312c009b35549677e8f4ff92bd156af328 --- /dev/null +++ b/view/flutter/demo_null_safety/android/app/src/main/kotlin/com/anjiplus/captcha/MainActivity.kt @@ -0,0 +1,12 @@ +package com.anjiplus.captcha + +import androidx.annotation.NonNull; +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugins.GeneratedPluginRegistrant + +class MainActivity: FlutterActivity() { + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine); + } +} diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/drawable/launch_background.xml b/view/flutter/demo_null_safety/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..304732f8842013497e14bd02f67a55f2614fb8f7 --- /dev/null +++ b/view/flutter/demo_null_safety/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..09d4391482be68e9e4a07fab769b5de337d16eb1 Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/values/styles.xml b/view/flutter/demo_null_safety/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..00fa4417cfbef8673c47c86eb24033fcd97056a8 --- /dev/null +++ b/view/flutter/demo_null_safety/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/view/flutter/demo_null_safety/android/app/src/profile/AndroidManifest.xml b/view/flutter/demo_null_safety/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba4ee87a2fc9f25967ca6df8b1213b93b6fdd881 --- /dev/null +++ b/view/flutter/demo_null_safety/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/view/flutter/demo_null_safety/android/build.gradle b/view/flutter/demo_null_safety/android/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..3100ad2d55532e58ed44b53dd3c2a04c5bcaf160 --- /dev/null +++ b/view/flutter/demo_null_safety/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/view/flutter/demo_null_safety/android/gradle.properties b/view/flutter/demo_null_safety/android/gradle.properties new file mode 100644 index 0000000000000000000000000000000000000000..38c8d4544ff1c4419409796aa6c1caee2c262ff7 --- /dev/null +++ b/view/flutter/demo_null_safety/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/view/flutter/demo_null_safety/android/gradle/wrapper/gradle-wrapper.properties b/view/flutter/demo_null_safety/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..296b146b7318dd58663296dbb7555df9ff328ec2 --- /dev/null +++ b/view/flutter/demo_null_safety/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/view/flutter/demo_null_safety/android/settings.gradle b/view/flutter/demo_null_safety/android/settings.gradle new file mode 100644 index 0000000000000000000000000000000000000000..5a2f14fb18f6e8b8c4308ff0f0dc187d9d27a5aa --- /dev/null +++ b/view/flutter/demo_null_safety/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/view/flutter/demo_null_safety/ios/.gitignore b/view/flutter/demo_null_safety/ios/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e96ef602b8d172f7cd28ba656aac097f741c736d --- /dev/null +++ b/view/flutter/demo_null_safety/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/view/flutter/demo_null_safety/ios/Flutter/AppFrameworkInfo.plist b/view/flutter/demo_null_safety/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000000000000000000000000000000000000..f2872cf474eee0cc0439d4012e1a653ac08e9d0f --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/view/flutter/demo_null_safety/ios/Flutter/Debug.xcconfig b/view/flutter/demo_null_safety/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000000000000000000000000000000000000..592ceee85b89bd111b779db6116b130509ab6d4b --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/view/flutter/demo_null_safety/ios/Flutter/Release.xcconfig b/view/flutter/demo_null_safety/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000000000000000000000000000000000000..592ceee85b89bd111b779db6116b130509ab6d4b --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.pbxproj b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000000000000000000000000000000..d63af51b714e5bee96a8e9bdd11641c951c2218b --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,503 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.anjiplus.captcha; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.anjiplus.captcha; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.anjiplus.captcha; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000000000000000000000000000000..919434a6254f0e9651f402737811be6634a03e9c --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/view/flutter/demo_null_safety/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000000000000000000000000000000000..3db53b6e1fb7f8a5fae6c2e6eb4e3b4382a3691e --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/view/flutter/demo_null_safety/ios/Runner.xcworkspace/contents.xcworkspacedata b/view/flutter/demo_null_safety/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000000000000000000000000000000..1d526a16ed0f1cd0c2409d848bf489b93fefa3b2 --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/view/flutter/demo_null_safety/ios/Runner/AppDelegate.swift b/view/flutter/demo_null_safety/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000000000000000000000000000000000000..70693e4a8c128fc4350b157416374ca599ac8c7b --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..d36b1fab2d9dea668a4f83df94d525897d9e68dd --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..28c6bf03016f6c994b70f38d1b7346e5831b531f Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2ccbfd967d9697cd4b83225558af2911e9571c9b Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cde12118dda48d71e01fcb589a74d069c5d7cb5 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..dcdc2306c28505ebc0b6c3a359c4d252bf626b9f Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..2ccbfd967d9697cd4b83225558af2911e9571c9b Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6a84f41e14e27f4b11f16f9ee39279ac98f8d5ac Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e1f58536026aebc4f1f70e481f6993c9ff088d Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..0bedcf2fd46788ae3a01a423467513ff59b5c120 --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000000000000000000000000000000000000..89c2725b70f1882be97f5214fafe22d27a0ec01e --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/view/flutter/demo_null_safety/ios/Runner/Base.lproj/LaunchScreen.storyboard b/view/flutter/demo_null_safety/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000000000000000000000000000000000..f2e259c7c9390ff69a6bbe1e0907e6dc366848e7 --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/view/flutter/demo_null_safety/ios/Runner/Base.lproj/Main.storyboard b/view/flutter/demo_null_safety/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000000000000000000000000000000000000..f3c28516fb38e64d88cfcf5fb1791175df078f2f --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/view/flutter/demo_null_safety/ios/Runner/Info.plist b/view/flutter/demo_null_safety/ios/Runner/Info.plist new file mode 100644 index 0000000000000000000000000000000000000000..88f1f9f56be876547f088fd75f13cab9a72a7edf --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + captcha + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + + diff --git a/view/flutter/demo_null_safety/ios/Runner/Runner-Bridging-Header.h b/view/flutter/demo_null_safety/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000000000000000000000000000000000000..7335fdf9000cec1b6c1e3f506b196734e8a427ff --- /dev/null +++ b/view/flutter/demo_null_safety/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/view/flutter/demo_null_safety/lib/captcha/block_puzzle_captcha.dart b/view/flutter/demo_null_safety/lib/captcha/block_puzzle_captcha.dart new file mode 100644 index 0000000000000000000000000000000000000000..1aececc2d0755ea6f3fc35fcd241b13e9bb4d045 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/captcha/block_puzzle_captcha.dart @@ -0,0 +1,545 @@ +import 'dart:convert'; +import 'dart:math'; + +import 'package:captcha/request/HttpManager.dart'; +import 'package:captcha/request/encrypt_util.dart'; +import 'package:captcha/tools/object_utils.dart'; +import 'package:captcha/tools/widget_util.dart'; +import 'package:flutter/material.dart'; +import 'package:steel_crypt/steel_crypt.dart'; +typedef VoidSuccessCallback = dynamic Function(String v); +class BlockPuzzleCaptchaPage extends StatefulWidget { + final VoidSuccessCallback? onSuccess; //拖放完成后验证成功回调 + final VoidCallback? onFail; //拖放完成后验证失败回调 + + BlockPuzzleCaptchaPage({this.onSuccess, this.onFail}); + + @override + _BlockPuzzleCaptchaPageState createState() => _BlockPuzzleCaptchaPageState(); +} + +class _BlockPuzzleCaptchaPageState extends State + with TickerProviderStateMixin { +// String baseImageBase64 = +// "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"; + String baseImageBase64 = ""; + String slideImageBase64 = ""; + String captchaToken = ""; + String secretKey = "";//加密key + + Size baseSize = Size.zero; //底部基类图片 + Size slideSize = Size.zero; //滑块图片 + + + var sliderColor = Colors.white; //滑块的背景色 + var sliderIcon = Icons.arrow_forward; //滑块的图标 + var movedXBorderColor = Colors.white; //滑块拖动时,左边已滑的区域边框颜色 + double sliderStartX = 0; //滑块未拖前的X坐标 + double sliderXMoved = 0; + bool sliderMoveFinish = false; //滑块拖动结束 + bool checkResultAfterDrag = false; //拖动后的校验结果 + + //-------------动画------------ + int _checkMilliseconds = 0; //滑动时间 + bool _showTimeLine = false; //是否显示动画部件 + bool _checkSuccess = false; //校验是否成功 + late AnimationController controller; + + //高度动画 + late Animation offsetAnimation; + + //底部部件key + GlobalKey _containerKey = new GlobalKey(); + //背景图key + GlobalKey _baseImageKey = new GlobalKey(); + //滑块 + GlobalKey _slideImageKey = new GlobalKey(); + double _bottomSliderSize = 60; + + + //------------动画------------ + + //校验通过 + void checkSuccess(String content) { + setState(() { + checkResultAfterDrag = true; + _checkSuccess = true; + _showTimeLine = true; + }); + _forwardAnimation(); + updateSliderColorIcon(); + + //刷新验证码 + Future.delayed(Duration(milliseconds: 1000)).then((v) { + _reverseAnimation().then((v) { + setState(() { + _showTimeLine = false; + }); + //回调 + if (widget.onSuccess != null) { + widget.onSuccess!(content); + } + //关闭验证码 + print(content); + Navigator.pop(context); + }); + }); + } + + //校验失败 + void checkFail() { + setState(() { + _showTimeLine = true; + _checkSuccess = false; + checkResultAfterDrag = false; + }); + _forwardAnimation(); + updateSliderColorIcon(); + + //刷新验证码 + Future.delayed(Duration(milliseconds: 1000)).then((v) { + _reverseAnimation().then((v) { + setState(() { + _showTimeLine = false; + }); + loadCaptcha(); + //回调 + if (widget.onFail != null) { + widget.onFail!(); + } + }); + }); + } + + //重设滑动颜色与图标 + void updateSliderColorIcon() { + var _sliderColor; //滑块的背景色 + var _sliderIcon; //滑块的图标 + var _movedXBorderColor; //滑块拖动时,左边已滑的区域边框颜色 + + //滑块的背景色 + if (sliderMoveFinish) { + //拖动结束 + _sliderColor = checkResultAfterDrag ? Colors.green : Colors.red; + _sliderIcon = checkResultAfterDrag ? Icons.check : Icons.close; + _movedXBorderColor = checkResultAfterDrag ? Colors.green : Colors.red; + } else { + //拖动未开始或正在拖动中 + _sliderColor = sliderXMoved > 0 ? Color(0xff447ab2) : Colors.white; + _sliderIcon = Icons.arrow_forward; + _movedXBorderColor = Color(0xff447ab2); + } + + sliderColor = _sliderColor; + sliderIcon = _sliderIcon; + movedXBorderColor = _movedXBorderColor; + setState(() {}); + } + + //加载验证码 + void loadCaptcha() { + setState(() { + _showTimeLine = false; + sliderMoveFinish = false; + checkResultAfterDrag = false; + sliderColor = Colors.white; //滑块的背景色 + sliderIcon = Icons.arrow_forward; //滑块的图标 + movedXBorderColor = Colors.white; //滑块拖动时,左边已滑的区域边框颜色 + }); + HttpManager.requestData( + '/captcha/get', {"captchaType": "blockPuzzle"}, {}) + .then((res) async { + if (res['repCode'] != '0000' || res['repData'] == null) { + setState(() { + secretKey = ""; + }); + return; + } + + Map repData = res['repData']; + sliderXMoved = 0; + sliderStartX = 0; + captchaToken = ''; + checkResultAfterDrag = false; + + baseImageBase64 = repData["originalImageBase64"]; + baseImageBase64 = repData["originalImageBase64"]; + secretKey = repData["secretKey"] ?? ""; + baseImageBase64 = baseImageBase64.replaceAll('\n', ''); + slideImageBase64 = repData["jigsawImageBase64"]; + slideImageBase64 = slideImageBase64.replaceAll('\n', ''); + captchaToken = repData["token"]; + + var baseR = await WidgetUtil.getImageWH( + image: Image.memory(Base64Decoder().convert(baseImageBase64))); + baseSize = baseR.size; + + var silderR = await WidgetUtil.getImageWH( + image: Image.memory(Base64Decoder().convert(slideImageBase64))); + slideSize = silderR.size; + + setState(() {}); + }).catchError((error) { + print(error); + }); + } + + //校验验证码 + void checkCaptcha(sliderXMoved, captchaToken, {BuildContext? myContext}) { + setState(() { + sliderMoveFinish = true; + }); + //滑动结束,改变滑块的图标及颜色 +// updateSliderColorIcon(); + + //pointJson参数需要aes加密 + +// MediaQueryData mediaQuery = MediaQuery.of(myContext); + var pointMap = {"x": sliderXMoved, "y": 5}; + var pointStr = json.encode(pointMap); + var cryptedStr = pointStr; + + // secretKey 不为空 进行as加密 + if(!ObjectUtils.isEmpty(secretKey)){ + cryptedStr = EncryptUtil.aesEncode(key: secretKey, content: pointStr); + var dcrypt = EncryptUtil.aesDecode(key: secretKey, content: cryptedStr); + json.decode(dcrypt); + + } + + + HttpManager.requestData('/captcha/check', { + "pointJson": cryptedStr, + "captchaType": "blockPuzzle", + "token": captchaToken + }, {}).then((res) { + if (res['repCode'] != '0000' || res['repData'] == null) { + checkFail(); + return; + } + + Map repData = res['repData']; + if (repData["result"] != null && repData["result"] == true) { + //如果不加密 将 token 和 坐标序列化 通过 --- 链接成字符串 + var captchaVerification = "$captchaToken---$pointStr"; + if(!ObjectUtils.isEmpty(secretKey)){ + //如果加密 将 token 和 坐标序列化 通过 --- 链接成字符串 进行加密 加密密钥为 _clickWordCaptchaModel.secretKey + captchaVerification = EncryptUtil.aesEncode(key: secretKey, content: captchaVerification); + } + checkSuccess(captchaVerification); + } else { + checkFail(); + } + }).catchError((error) { + loadCaptcha(); + print(error); + }); + } + + @override + void initState() { + super.initState(); + initAnimation(); + loadCaptcha(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + // 初始化动画 + void initAnimation() { + controller = + AnimationController(duration: Duration(milliseconds: 500), vsync: this); + + offsetAnimation = Tween(begin: 0.5, end: 0) + .animate(CurvedAnimation(parent: controller, curve: Curves.ease)) + ..addListener(() { + this.setState(() {}); + }); + } + + // 反向执行动画 + _reverseAnimation() async { + await controller.reverse(); + } + + // 正向执行动画 + _forwardAnimation() async { + await controller.forward(); + } + + @override + void didUpdateWidget(BlockPuzzleCaptchaPage oldWidget) { + // TODO: implement didUpdateWidget + super.didUpdateWidget(oldWidget); + } + + @override + Widget build(BuildContext context) { + return MaxScaleTextWidget( + child: buildContent(context), + ); + } + + Widget buildContent(BuildContext context) { + var mediaQuery = MediaQuery.of(context); + var dialogWidth = 0.9 * mediaQuery.size.width; + if (dialogWidth < 330) { + dialogWidth = mediaQuery.size.width; + } + + return Scaffold( + backgroundColor: Colors.transparent, + body: Center( + child: Container( + key: _containerKey, + width: dialogWidth, + height: 340, + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _topContainer(), + _middleContainer(), + _bottomContainer(), + ], + ), + ), + ), + ); + } + + ///顶部,提示+关闭 + _topContainer() { + return Container( + height: 50, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: Color(0xffe5e5e5))), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '请完成安全验证', + style: TextStyle(fontSize: 18), + ), + IconButton( + icon: Icon(Icons.highlight_off), + iconSize: 30, + color: Colors.black38, + onPressed: () { + //退出 + Navigator.pop(context); + }), + ], + ), + ); + } + + _middleContainer() { + ////显示验证码 + return Container( + margin: EdgeInsets.symmetric(vertical: 10), + child: Stack( + children: [ + ///底图 310*155 + baseImageBase64.length > 0 + ? Image.memory( + Base64Decoder().convert(baseImageBase64), + fit: BoxFit.fitWidth, + key: _baseImageKey, + gaplessPlayback: true, + ) + : Container( + width: 310, + height: 155, + alignment: Alignment.center, + child: CircularProgressIndicator(), + ), + + ///滑块图 + slideImageBase64.length > 0 + ? Container( + margin: EdgeInsets.fromLTRB(sliderXMoved, 0, 0, 0), + child: Image.memory( + Base64Decoder().convert(slideImageBase64), + fit: BoxFit.fitHeight, + key: _slideImageKey, + gaplessPlayback: true, + ), + ) + : Container(), + + //刷新按钮 + Positioned( + top: 0, + right: 0, + child: IconButton( + icon: Icon(Icons.refresh), + iconSize: 30, + color: Colors.black54, + onPressed: () { + //刷新 + loadCaptcha(); + }), + ), + Positioned( + bottom: 0, + left: -10, + right: -10, + child: Offstage( + offstage: !_showTimeLine, + child: FractionalTranslation( + translation: Offset(0, offsetAnimation.value), + child: Container( + margin: EdgeInsets.only(left: 10, right: 10), + height: 40, + color: _checkSuccess + ? Color(0x7F66BB6A) + : Color.fromRGBO(200, 100, 100, 0.4), + alignment: Alignment.centerLeft, + child: Text( + _checkSuccess + ? "${(_checkMilliseconds / (60.0 * 12)).toStringAsFixed(2)}s验证成功" + : "验证失败", + style: TextStyle(color: Colors.white), + ), + ), + ), + )), + Positioned( + bottom: -20, + left: 0, + right: 0, + child: Offstage( + offstage: !_showTimeLine, + child: Container( + margin: EdgeInsets.only(left: 10, right: 10), + height: 20, + color: Colors.white, + ), + )) + ], + ), + ); + } + ///底部,滑动区域 + _bottomContainer() { + return baseSize.width >0 + ? Container( + height: 70, + width: baseSize.width, +// color: Colors.cyanAccent, + child: Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + Container( + height: _bottomSliderSize, + decoration: BoxDecoration( + border: Border.all( + width: 1, + color: Color(0xffe5e5e5), + ), + color: Color(0xfff8f9fb), + ), + ), + Container( + alignment: Alignment.center, + child: Text( + '向右拖动滑块填充拼图', + style: TextStyle(fontSize: 16), + ), + ), + Container( + width: sliderXMoved, + height: _bottomSliderSize-2, + decoration: BoxDecoration( + border: Border.all( + width: sliderXMoved > 0 ? 1 : 0, + color: movedXBorderColor, + ), + color: Color(0xfff3fef1), + ), + ), + GestureDetector( + onPanStart: (startDetails) {///开始 + _checkMilliseconds = new DateTime.now().millisecondsSinceEpoch; + print(startDetails.localPosition); + sliderStartX = startDetails.localPosition.dx; + }, + onPanUpdate: (updateDetails) { ///更新 + print(updateDetails.localPosition); + double _w1 = _baseImageKey.currentContext!.size!.width - _slideImageKey.currentContext!.size!.width; + double offset = updateDetails.localPosition.dx - sliderStartX; + if(offset < 0){ + offset = 0; + } + if(offset > _w1){ + offset = _w1; + } + print("offset ------ $offset"); + setState(() { + sliderXMoved = offset; + }); + //滑动过程,改变滑块左边框颜色 + updateSliderColorIcon(); + }, + onPanEnd: (endDetails) { //结束 + print("endDetails"); + checkCaptcha(sliderXMoved, captchaToken); + int _nowTime = new DateTime.now().millisecondsSinceEpoch; + _checkMilliseconds = _nowTime - _checkMilliseconds; + }, + child: Container( + width: _bottomSliderSize, + height: _bottomSliderSize, + margin: EdgeInsets.only(left: sliderXMoved > 0 ? sliderXMoved : 1), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: 1, + color: Color(0xffe5e5e5), + ), + right: BorderSide( + width: 1, + color: Color(0xffe5e5e5), + ), + bottom: BorderSide( + width: 1, + color: Color(0xffe5e5e5), + ), + ), + color: sliderColor, + ), + child: IconButton( + icon: Icon(sliderIcon), + iconSize: 30, + color: Colors.black54, onPressed: () { }, + ), + ), + ) + ], + )) + : Container(); + } +} + + +class MaxScaleTextWidget extends StatelessWidget { + final double max; + final Widget child; + + MaxScaleTextWidget({Key? key, this.max = 1.0, required this.child}) : super(key: key); + + @override + Widget build(BuildContext context) { + var data = MediaQuery.of(context); + var textScaleFactor = min(max, data.textScaleFactor); + return MediaQuery(data: data.copyWith(textScaleFactor: textScaleFactor), child: child); + } +} diff --git a/view/flutter/demo_null_safety/lib/captcha/click_word_captcha.dart b/view/flutter/demo_null_safety/lib/captcha/click_word_captcha.dart new file mode 100644 index 0000000000000000000000000000000000000000..56e1f2e3572abd75d15c1e1547be358cf7d57af5 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/captcha/click_word_captcha.dart @@ -0,0 +1,367 @@ +import 'dart:convert'; + +import 'package:captcha/request/HttpManager.dart'; +import 'package:captcha/request/encrypt_util.dart'; +import 'package:captcha/tools/object_utils.dart'; +import 'package:captcha/tools/widget_util.dart'; +import 'package:flutter/material.dart'; +import 'package:steel_crypt/steel_crypt.dart'; + +typedef VoidSuccessCallback = dynamic Function(String v); + +class ClickWordCaptcha extends StatefulWidget { + final VoidSuccessCallback? onSuccess; //文字点击后验证成功回调 + final VoidCallback? onFail; //文字点击完成后验证失败回调 + + const ClickWordCaptcha({Key? key, this.onSuccess, this.onFail}) + : super(key: key); + + @override + _ClickWordCaptchaState createState() => _ClickWordCaptchaState(); +} + +class _ClickWordCaptchaState extends State { + ClickWordCaptchaState _clickWordCaptchaState = ClickWordCaptchaState.none; + List _tapOffsetList = []; + ClickWordCaptchaModel _clickWordCaptchaModel = ClickWordCaptchaModel(); + + Color titleColor = Colors.black; + Color borderColor = Color(0xffdddddd); + String bottomTitle = ""; + Size baseSize = Size(310.0, 155.0); + + //改变底部样式及字段 + _changeResultState() { + switch (_clickWordCaptchaState) { + case ClickWordCaptchaState.normal: + titleColor = Colors.black; + borderColor = Color(0xffdddddd); + break; + case ClickWordCaptchaState.success: + _tapOffsetList = []; + titleColor = Colors.green; + borderColor = Colors.green; + bottomTitle = "验证成功"; + break; + case ClickWordCaptchaState.fail: + _tapOffsetList = []; + titleColor = Colors.red; + borderColor = Colors.red; + bottomTitle = "验证失败"; + break; + default: + titleColor = Colors.black; + borderColor = Color(0xffdddddd); + bottomTitle = "数据加载中……"; + break; + } + setState(() {}); + } + + @override + void initState() { + super.initState(); + _loadCaptcha(); + } + + //加载验证码 + _loadCaptcha() async { + _tapOffsetList = []; + _clickWordCaptchaState = ClickWordCaptchaState.none; + _changeResultState(); + var res = await HttpManager.requestData( + '/captcha/get', {"captchaType": "clickWord"}, {}); + if (res['repCode'] != '0000' || res['repData'] == null) { + _clickWordCaptchaModel.secretKey = ""; + bottomTitle = "加载失败,请刷新"; + _clickWordCaptchaState = ClickWordCaptchaState.normal; + _changeResultState(); + return; + } else { + Map repData = res['repData']; + _clickWordCaptchaModel = ClickWordCaptchaModel.fromMap(repData); + + var baseR = await WidgetUtil.getImageWH( + image: Image.memory( + Base64Decoder().convert(_clickWordCaptchaModel.imgStr))); + baseSize = baseR.size; + + bottomTitle = "请依次点击【${_clickWordCaptchaModel.wordStr}】"; + } + + _clickWordCaptchaState = ClickWordCaptchaState.normal; + _changeResultState(); + } + + //校验验证码 + _checkCaptcha() async { + List> mousePos = []; + _tapOffsetList.map((size) { + mousePos + .add({"x": size.dx.roundToDouble(), "y": size.dy.roundToDouble()}); + }).toList(); + var pointStr = json.encode(mousePos); + + var cryptedStr = pointStr; + + // secretKey 不为空 进行as加密 + if (!ObjectUtils.isEmpty(_clickWordCaptchaModel.secretKey)) { + cryptedStr = EncryptUtil.aesEncode( + key: _clickWordCaptchaModel.secretKey, content: pointStr); + var dcrypt = EncryptUtil.aesDecode( + key: _clickWordCaptchaModel.secretKey, content: cryptedStr); + } + +// Map _map = json.decode(dcrypt); + var res = await HttpManager.requestData('/captcha/check', { + "pointJson": cryptedStr, + "captchaType": "clickWord", + "token": _clickWordCaptchaModel.token + }, {}); + if (res['repCode'] != '0000' || res['repData'] == null) { + _checkFail(); + return; + } + Map repData = res['repData']; + if (repData["result"] != null && repData["result"] == true) { + //如果不加密 将 token 和 坐标序列化 通过 --- 链接成字符串 + var captchaVerification = "${_clickWordCaptchaModel.token}---$pointStr"; + if (!ObjectUtils.isEmpty(_clickWordCaptchaModel.secretKey)) { + //如果加密 将 token 和 坐标序列化 通过 --- 链接成字符串 进行加密 加密密钥为 _clickWordCaptchaModel.secretKey + captchaVerification = EncryptUtil.aesEncode( + key: _clickWordCaptchaModel.secretKey, + content: captchaVerification); + } + _checkSuccess(captchaVerification); + } else { + _checkFail(); + } + } + + //校验失败 + _checkFail() async { + _clickWordCaptchaState = ClickWordCaptchaState.fail; + _changeResultState(); + + await Future.delayed(Duration(milliseconds: 1000)); + _loadCaptcha(); + //回调 + if (widget.onFail != null) { + widget.onFail!(); + } + } + + //校验成功 + _checkSuccess(String pointJson) async { + _clickWordCaptchaState = ClickWordCaptchaState.success; + _changeResultState(); + + await Future.delayed(Duration(milliseconds: 1000)); + + var cryptedStr = EncryptUtil.aesEncode(key: 'BGxdEUOZkXka4HSj', content: pointJson); + + print(cryptedStr); + //回调 pointJson 是经过es加密之后的信息 + if (widget.onSuccess != null) { + widget.onSuccess!(cryptedStr); + } + //关闭 + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + var data = MediaQuery.of(context); + var dialogWidth = 0.9 * data.size.width; + var isRatioCross = false; + if (dialogWidth < 320.0) { + dialogWidth = data.size.width; + isRatioCross = true; + } + return Scaffold( + backgroundColor: Colors.transparent, + body: Center( + child: Container( + width: dialogWidth, + height: 320, + color: Colors.white, + child: Column( + children: [ + _topConttainer(), + _captchaContainer(), + _bottomContainer() + ], + ), + ), + ), + ); + } + + //图片验证码 + _captchaContainer() { + List _widgetList = []; + if (!ObjectUtils.isEmpty(_clickWordCaptchaModel.imgStr)) { + _widgetList.add(Image( + width: baseSize.width, + height: baseSize.height, + gaplessPlayback: true, + image: MemoryImage( + Base64Decoder().convert(_clickWordCaptchaModel.imgStr)))); + } + + double _widgetW = 20; + for (int i = 0; i < _tapOffsetList.length; i++) { + Offset offset = _tapOffsetList[i]; + _widgetList.add(Positioned( + left: offset.dx - _widgetW * 0.5, + top: offset.dy - _widgetW * 0.5, + child: Container( + alignment: Alignment.center, + width: _widgetW, + height: _widgetW, + decoration: BoxDecoration( + color: Color(0xCC43A047), + borderRadius: BorderRadius.all(Radius.circular(_widgetW))), + child: Text( + "${i + 1}", + style: TextStyle(color: Colors.white, fontSize: 15), + ), + ))); + } + _widgetList.add(//刷新按钮 + Positioned( + top: 0, + right: 0, + child: IconButton( + icon: Icon(Icons.refresh), + iconSize: 30, + color: Colors.deepOrangeAccent, + onPressed: () { + //刷新 + _loadCaptcha(); + }), + )); + + return GestureDetector( + onTapDown: (TapDownDetails details) { + debugPrint( + "onTapDown globalPosition全局坐标系位置: ${details.globalPosition} localPosition组件坐标系位置: ${details.localPosition} "); + if (!ObjectUtils.isListEmpty(_clickWordCaptchaModel.wordList) && + _tapOffsetList.length < _clickWordCaptchaModel.wordList.length) { + _tapOffsetList.add( + Offset(details.localPosition.dx, details.localPosition.dy)); + } + setState(() {}); + if (!ObjectUtils.isListEmpty(_clickWordCaptchaModel.wordList) && + _tapOffsetList.length == _clickWordCaptchaModel.wordList.length) { + _checkCaptcha(); + } + }, + child: Container( + width: baseSize.width, + height: baseSize.height, + child: Stack( + children: _widgetList, + ), + )); + } + + //底部提示部件 + _bottomContainer() { + return Container( + height: 50, + margin: EdgeInsets.only(top: 10), + alignment: Alignment.center, + width: baseSize.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(4)), + border: Border.all(color: borderColor)), + child: + Text(bottomTitle, style: TextStyle(fontSize: 18, color: titleColor)), + ); + } + + //顶部,提示+关闭 + _topConttainer() { + return Container( + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + margin: EdgeInsets.only(bottom: 20, top: 5), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: Color(0xffe5e5e5))), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '请完成安全验证', + style: TextStyle(fontSize: 18), + ), + IconButton( + icon: Icon(Icons.highlight_off), + iconSize: 35, + color: Colors.black54, + onPressed: () { + //退出 + Navigator.pop(context); + }), + ], + ), + ); + } +} + +//校验状态 +enum ClickWordCaptchaState { + normal, //默认 可自定义描述 + success, //成功 + fail, //失败 + none, //无状态 用于加载使用 +} + +//请求数据模型 +class ClickWordCaptchaModel { + String imgStr; //图表url 目前用base64 data + String token; // 获取的token 用于校验 + List wordList; //显示需要点选的字 + String wordStr; //显示需要点选的字转换为字符串 + String secretKey; //加密key + + ClickWordCaptchaModel( + {this.imgStr = "", + this.token = "", + this.secretKey = "", + this.wordList = const [], + this.wordStr = ""}); + + //解析数据转换模型 + static ClickWordCaptchaModel fromMap(Map map) { + ClickWordCaptchaModel captchaModel = ClickWordCaptchaModel(); + captchaModel.imgStr = map["originalImageBase64"] ?? ""; + captchaModel.token = map["token"] ?? ""; + captchaModel.secretKey = map["secretKey"] ?? ""; + captchaModel.wordList = map["wordList"] ?? []; + + if (!ObjectUtils.isListEmpty(captchaModel.wordList)) { + captchaModel.wordStr = captchaModel.wordList.join(","); + } + + return captchaModel; + } + + //将模型转换 + Map toJson() { + var map = new Map(); + map['imgStr'] = imgStr; + map['token'] = token; + map['secretKey'] = token; + map['wordList'] = wordList; + map['wordStr'] = wordStr; + return map; + } + + @override + String toString() { + // TODO: implement toString + return JsonEncoder.withIndent(' ').convert(toJson()); + } +} diff --git a/view/flutter/demo_null_safety/lib/demo.dart b/view/flutter/demo_null_safety/lib/demo.dart new file mode 100644 index 0000000000000000000000000000000000000000..dee4c86990b297828ace6c894c43687f21c65f21 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/demo.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class DemoPage extends StatefulWidget { + + @override + _DemoPageState createState() => _DemoPageState(); +} + +class _DemoPageState extends State { + @override + Widget build(BuildContext context) { + // TODO: implement build + return Scaffold( + appBar: AppBar( + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text('title'), + ), + body: Container(), + ); + } + +} \ No newline at end of file diff --git a/view/flutter/demo_null_safety/lib/login.dart b/view/flutter/demo_null_safety/lib/login.dart new file mode 100644 index 0000000000000000000000000000000000000000..13b4bc82c147e5de07a19e6c392cab2d122c6bf0 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/login.dart @@ -0,0 +1,122 @@ +import 'package:captcha/captcha/click_word_captcha.dart'; +import 'package:flutter/material.dart'; + +import 'package:captcha/captcha/block_puzzle_captcha.dart'; + +class LoginPage extends StatefulWidget { + @override + _LoginPageState createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + + List getListData(){ + List items= []; + DropdownMenuItem dropdownMenuItem1=new DropdownMenuItem( + child:new Text('滑动拼图'), + value: 1, + ); + items.add(dropdownMenuItem1); + DropdownMenuItem dropdownMenuItem2=new DropdownMenuItem( + child:new Text('文字点选'), + value: 2, + ); + items.add(dropdownMenuItem2); + + return items; + } + + int? value; + + + @override + Widget build(BuildContext context) { + // TODO: implement build + return Scaffold( + appBar: AppBar( + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text('title'), + ), + body: Container( + alignment: Alignment.center, + child: Column( + children: [ + TextField( + decoration: InputDecoration( + icon: Icon(Icons.person), + labelText: "用户名", + labelStyle: TextStyle( + color: Colors.red, + fontSize: 20, + )), + ), + TextField( + decoration: InputDecoration( + icon: Icon(Icons.lock), + labelText: "密码", + labelStyle: TextStyle( + color: Colors.red, + fontSize: 20, + )), + ), + DropdownButton( + items: getListData(), + hint:new Text('登录'),//当没有默认值的时候可以设置的提示 + value: value,//下拉菜单选择完之后显示给用户的值 + onChanged: (v){//下拉菜单item点击之后的回调 + if(v == 1){ + loadingBlockPuzzle(context); + } else { + loadingClickWord(context); + } + }, + elevation: 24,//设置阴影的高度 + style: new TextStyle(//设置文本框里面文字的样式 + color: Colors.red + ), +// isDense: false,//减少按钮的高度。默认情况下,此按钮的高度与其菜单项的高度相同。如果isDense为true,则按钮的高度减少约一半。 这个当按钮嵌入添加的容器中时,非常有用 + iconSize: 50.0,//设置三角标icon的大小 + ) + ], + ), + ), + ); + } + + //点选拼图 + static void loadingClickWord(BuildContext context, {barrierDismissible = true}) { + showDialog( + context: context, + barrierDismissible: barrierDismissible, + builder: (BuildContext context) { + return ClickWordCaptcha( + onSuccess: (v){ + + }, + onFail: (){ + + }, + ); + }, + ); + } + + //滑动拼图 + static void loadingBlockPuzzle(BuildContext context, {barrierDismissible = true}) { + showDialog( + context: context, + barrierDismissible: barrierDismissible, + builder: (BuildContext context) { + return BlockPuzzleCaptchaPage( + onSuccess: (v){ + + }, + onFail: (){ + + }, + ); + }, + ); + } +} diff --git a/view/flutter/demo_null_safety/lib/main.dart b/view/flutter/demo_null_safety/lib/main.dart new file mode 100644 index 0000000000000000000000000000000000000000..b7695ea1055cadd900f0e23af4f3bd7f0f5ae110 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/main.dart @@ -0,0 +1,27 @@ +import 'package:captcha/login.dart'; +import 'package:flutter/material.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primarySwatch: Colors.blue, + ), + home: LoginPage(), + ); + } +} diff --git a/view/flutter/demo_null_safety/lib/request/HttpManager.dart b/view/flutter/demo_null_safety/lib/request/HttpManager.dart new file mode 100644 index 0000000000000000000000000000000000000000..3fe85b25f248cfdc81483481573bd0595227080c --- /dev/null +++ b/view/flutter/demo_null_safety/lib/request/HttpManager.dart @@ -0,0 +1,90 @@ +import 'dart:io'; + +import 'package:captcha/request/SignConfig.dart'; +import 'package:dio/dio.dart'; +import 'dart:collection'; + + +///http请求 +class HttpManager { + static const CONTENT_TYPE_JSON = "application/json"; + static const CONTENT_TYPE_FORM = "application/x-www-form-urlencoded"; + static Map optionParams = { + "mirrorToken": null, + "content-Type": CONTENT_TYPE_JSON + }; + + //请求base url + //todo 请求host配置 + static String baseUrl = "http://127.0.0.1:8080"; +// static late String baseUrl; + + ///发起网络请求 + ///[ url] 请求url + ///[ param] 请求参数 + ///[ header] 外加头 + ///[ isNeedToken] 是否需要token + ///[ optionMetod] 请求类型 post、get + ///[ noTip] 是否需要返回错误信息 默认不需要 + ///[ needSign] 是否需要Sign校验 默认需要 + ///[ needError] 是否需要错误提示 + static requestData(url, param, Map? header, + {bool isNeedToken = true, + String optionMetod = "post", + noTip = false, + needSign = true, + needError = true}) async { + ///初始化请求类 + Dio dio = Dio(); + + ///头部 + Map headers = HashMap(); + if (header != null) { + headers.addAll(header); + } + + //请求协议 post 、get + Options option = Options(method: optionMetod); + + ///设置头部 + option.headers = headers; + + option.sendTimeout = 15000; + + //获取token + // var mirrorToken = ""; + + var params = param; +// if (needSign) { +// //获取加密的请求参数 +// params = await SignConfig.signData(param, mirrorToken); +// } + + late Response response; + try { + ///开始请求 + response = + await dio.request("$baseUrl$url", data: params, options: option); + } on DioError catch (e) { + if (e.response != null) { + } else { + } + + ///请求失败处理 + if (needError) { + return e; + } + } + + try { + var responseJson = response.data; + if (response.statusCode == 200) { + ///请求链接成功 + return responseJson; + } + } catch (e) { + print(e.toString()); + throw e; + } + } +} diff --git a/view/flutter/demo_null_safety/lib/request/SignConfig.dart b/view/flutter/demo_null_safety/lib/request/SignConfig.dart new file mode 100644 index 0000000000000000000000000000000000000000..15baa7c51157e3400999cc28695920a9fba80644 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/request/SignConfig.dart @@ -0,0 +1,46 @@ +import 'dart:convert'; +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; + +class SignConfig { + + + static String generateMd5(String data){ + var content = new Utf8Encoder().convert(data); + var digest = md5.convert(content); + return hex.encode(digest.bytes); + } + + static signData(Object params, tokenStr) async { + var time = new DateTime.now().millisecondsSinceEpoch; + String token = tokenStr; + Map reqData = new Map(); + Map? paramsObj = new Map(); + paramsObj = params as Map?; + var arr = []; + //将字典转成数组 + paramsObj?.forEach((key, value) => arr.add(key)); + //进行签名校验 + Map cr = new Map(); + cr['token'] = token; + cr['time'] = time.toString(); + cr['reqData'] = json.encode(paramsObj); + var array = []; + cr.forEach((key, value) => array.add(key)); + array.sort(); + var str = ''; + for (var i = 0; i < array.length; i++) { + var key = array[i]; + var value = cr[key]; + str += key + value; + } + + reqData["time"] = time; + reqData["token"] = token; + reqData['reqData'] = params; + reqData['sign'] = generateMd5(str); + + return reqData; + } + +} \ No newline at end of file diff --git a/view/flutter/demo_null_safety/lib/request/encrypt_util.dart b/view/flutter/demo_null_safety/lib/request/encrypt_util.dart new file mode 100644 index 0000000000000000000000000000000000000000..2b7ff84585212dc933cbb3564e680134373a0db8 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/request/encrypt_util.dart @@ -0,0 +1,30 @@ +import 'dart:convert'; + +import 'package:steel_crypt/steel_crypt.dart'; +//import 'package:encrypt/encrypt.dart'; + +class EncryptUtil { + + ///aes加密 + /// [key]AesCrypt加密key + /// [content] 需要加密的内容字符串 + static String aesEncode({required String key, required String content}) { + var aesCrypt = AesCrypt( + key: base64UrlEncode(key.codeUnits), padding: PaddingAES.pkcs7); + return aesCrypt.ecb.encrypt(inp: content); + } + + ///aes解密 + /// [key]aes解密key + /// [content] 需要加密的内容字符串 + static String aesDecode({required String key, required String content}) { + var aesCrypt = AesCrypt( + key: base64UrlEncode(key.codeUnits), padding: PaddingAES.pkcs7); + return aesCrypt.ecb.decrypt(enc: content); + } + + + + + +} \ No newline at end of file diff --git a/view/flutter/demo_null_safety/lib/tools/object_utils.dart b/view/flutter/demo_null_safety/lib/tools/object_utils.dart new file mode 100644 index 0000000000000000000000000000000000000000..92208acd53b4154973ea2fff7f093adb5facc230 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/tools/object_utils.dart @@ -0,0 +1,27 @@ +import 'dart:convert'; + +class ObjectUtils { + /// isEmpty. + static bool isEmpty(Object? value) { + if (value == null) return true; + if (value is String && value.isEmpty) { + return true; + } + return false; + } + + //list length == 0 || list == null + static bool isListEmpty(Object? value) { + if (value == null) return true; + if (value is List && value.length == 0) { + return true; + } + return false; + } + + static String jsonFormat(Map map) { + Map _map = Map.from(map); + JsonEncoder encoder = JsonEncoder.withIndent(' '); + return encoder.convert(_map); + } +} diff --git a/view/flutter/demo_null_safety/lib/tools/widget_util.dart b/view/flutter/demo_null_safety/lib/tools/widget_util.dart new file mode 100644 index 0000000000000000000000000000000000000000..16e72442e6c22a18eea3b4eb6754522d33dc0b04 --- /dev/null +++ b/view/flutter/demo_null_safety/lib/tools/widget_util.dart @@ -0,0 +1,133 @@ +import 'dart:async'; + +import 'package:flutter/widgets.dart'; + +import 'object_utils.dart'; +/** + * @Author: thl + * @GitHub: https://github.com/Sky24n + * @Email: 863764940@qq.com + * @Email: sky24no@gmail.com + * @Description: Widget Util. + * @Date: 2018/9/10 + */ + +/// Widget Util. +class WidgetUtil { + bool _hasMeasured = false; + late double _width; + late double _height; + + /// Widget rendering listener. + /// Widget渲染监听. + /// context: Widget context. + /// isOnce: true,Continuous monitoring false,Listen only once. + /// onCallBack: Widget Rect CallBack. + void asyncPrepare( + BuildContext context, bool isOnce, ValueChanged onCallBack) { + if (_hasMeasured) return; + WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { + RenderObject? box = context.findRenderObject(); + if (box != null) { + if (isOnce) _hasMeasured = true; + double width = box.semanticBounds.width; + double height = box.semanticBounds.height; + if (_width != width || _height != height) { + _width = width; + _height = height; + if (onCallBack != null) onCallBack(box.semanticBounds); + } + } + }); + } + + /// Widget渲染监听. + void asyncPrepares(bool isOnce, ValueChanged? onCallBack) { + if (_hasMeasured) return; + WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { + if (isOnce) _hasMeasured = true; + if (onCallBack != null) onCallBack(null); + }); + } + + ///get Widget Bounds (width, height, left, top, right, bottom and so on).Widgets must be rendered completely. + ///获取widget Rect + static Rect getWidgetBounds(BuildContext context) { + RenderObject? box = context.findRenderObject(); + return (box != null) ? box.semanticBounds : Rect.zero; + } + + ///Get the coordinates of the widget on the screen.Widgets must be rendered completely. + ///获取widget在屏幕上的坐标,widget必须渲染完成 + static Offset getWidgetLocalToGlobal(BuildContext context) { + RenderBox? box = context.findRenderObject() as RenderBox?; + return box == null ? Offset.zero : box.localToGlobal(Offset.zero); + } + + /// get image width height,load error return Rect.zero.(unit px) + /// 获取图片宽高,加载错误情况返回 Rect.zero.(单位 px) + /// image + /// url network + /// local url , package + static Future getImageWH( + {Image? image, String? url, String? localUrl, String? package}) { + if (ObjectUtils.isEmpty(image) && + ObjectUtils.isEmpty(url) && + ObjectUtils.isEmpty(localUrl)) { + return Future.value(Rect.zero); + } + Completer completer = Completer(); + Image img = image ?? ((url != null && url.isNotEmpty) + ? Image.network(url) + : Image.asset(localUrl!, package: package)); + img.image + .resolve(const ImageConfiguration()) + .addListener(ImageStreamListener( + (ImageInfo info, bool _) { + completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(), + info.image.height.toDouble())); + }, + onError: (Object exception, StackTrace? stackTrace) { + completer.completeError(exception, stackTrace); + }, + )); + return completer.future; + } + + /// get image width height, load error throw exception.(unit px) + /// 获取图片宽高,加载错误会抛出异常.(单位 px) + /// image + /// url network + /// local url (full path/全路径,example:"assets/images/ali_connors.png",""assets/images/3.0x/ali_connors.png"" ); + /// package + static Future getImageWHE( + {Image? image, + required String url, + required String localUrl, + required String package}) { + if (ObjectUtils.isEmpty(image) && + ObjectUtils.isEmpty(url) && + ObjectUtils.isEmpty(localUrl)) { + return Future.error("image is null."); + } + Completer completer = Completer(); + Image img = image != null + ? image + : ((url != null && url.isNotEmpty) + ? Image.network(url) + : Image.asset(localUrl, package: package)); + img.image + .resolve(const ImageConfiguration()) + .addListener(ImageStreamListener( + (ImageInfo info, bool _) { + completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(), + info.image.height.toDouble())); + }, + onError: (Object exception, StackTrace? stackTrace) { + completer.completeError(exception, stackTrace); + }, + )); + + return completer.future; + } +} diff --git a/view/flutter/demo_null_safety/pubspec.lock b/view/flutter/demo_null_safety/pubspec.lock new file mode 100644 index 0000000000000000000000000000000000000000..38a40a70458ba0fa20f86a6f1681d70875e9cd0b --- /dev/null +++ b/view/flutter/demo_null_safety/pubspec.lock @@ -0,0 +1,230 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" + asn1lib: + dependency: transitive + description: + name: asn1lib + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.0" + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.6" + encrypt: + dependency: "direct main" + description: + name: encrypt + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.1" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.2" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.5" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.2" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + steel_crypt: + dependency: "direct main" + description: + name: steel_crypt + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0+1" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.9" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" +sdks: + dart: ">=2.17.0-0 <3.0.0" diff --git a/view/flutter/demo_null_safety/pubspec.yaml b/view/flutter/demo_null_safety/pubspec.yaml new file mode 100644 index 0000000000000000000000000000000000000000..361a8439224302d9a0971f0a45793e79b6b827d6 --- /dev/null +++ b/view/flutter/demo_null_safety/pubspec.yaml @@ -0,0 +1,75 @@ +name: captcha +description: A new Flutter application. + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 2.0.0+1 + +environment: + sdk: ">=2.12.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.5 + + dio: ^4.0.6 + steel_crypt: ^3.0.0+1 + encrypt: ^5.0.1 + +dev_dependencies: + flutter_test: + sdk: flutter + + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + #assets: + # - assets/ + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/view/flutter/demo_null_safety/test/widget_test.dart b/view/flutter/demo_null_safety/test/widget_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..ed8f89454c18cde1239a940912992de84b8ed4c6 --- /dev/null +++ b/view/flutter/demo_null_safety/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:captcha/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/view/php/index.php b/view/php/index.php index 8b87517192398fe3eaf7a2245af30d1e1b6f911e..db85035e29324914a6fa16b2e661fc74ac9457bc 100644 --- a/view/php/index.php +++ b/view/php/index.php @@ -11,7 +11,7 @@ if($requestUri == '/captcha/get'){ $payload = file_get_contents('php://input'); header('Content-Type: application/json;charset=UTF-8'); header('Transfer-Encoding: chunked'); - echo AjCaptcharHelper::ostRequest('https://captcha.anji-plus.com/captcha-api/captcha/check', $payload); + echo AjCaptcharHelper::postRequest('https://captcha.anji-plus.com/captcha-api/captcha/check', $payload); }elseif($requestUri == '/captcha/verify'){ $payload = file_get_contents('php://input'); header('Content-Type: application/json;charset=UTF-8'); diff --git a/view/vue3/src/components/verifition/Verify/VerifySlide.vue b/view/vue3/src/components/verifition/Verify/VerifySlide.vue index fcd18a586aabb56f525273b1fb1e50ad76b686f4..73c8a9ab55f9ffffd4a917d3bf27d7912aff7c71 100644 --- a/view/vue3/src/components/verifition/Verify/VerifySlide.vue +++ b/view/vue3/src/components/verifition/Verify/VerifySlide.vue @@ -33,7 +33,7 @@ 'top':'-' + (parseInt(setSize.imgHeight) + vSpace) + 'px', 'background-size': setSize.imgWidth + ' ' + setSize.imgHeight, }"> - + @@ -223,11 +223,11 @@ } var bar_area_left = barArea.value.getBoundingClientRect().left; var move_block_left = x - bar_area_left //小方块相对于父元素的left值 - if (move_block_left >= barArea.value.offsetWidth - parseInt(parseInt(blockSize.width) / 2) - 2) { - move_block_left = barArea.value.offsetWidth - parseInt(parseInt(blockSize.width) / 2) - 2; + if (move_block_left >= barArea.value.offsetWidth - parseInt(parseInt(blockSize.value.width) / 2) - 2) { + move_block_left = barArea.value.offsetWidth - parseInt(parseInt(blockSize.value.width) / 2) - 2; } if (move_block_left <= 0) { - move_block_left = parseInt(parseInt(blockSize.width) / 2); + move_block_left = parseInt(parseInt(blockSize.value.width) / 2); } //拖动后小方块的left值 moveBlockLeft.value = (move_block_left - startLeft.value) + "px"