admin
2022-01-20 d8ef9a783b9e0b2a495f02fdf3daaf27ef49e99d
flutter模板
8个文件已修改
108个文件已添加
7940 ■■■■■ 已修改文件
src/main/resources/code/android/app/src/main/java/com/demo/app/utils/Constant.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/app/src/main/java/com/demo/app/utils/browser/MyJavaInterface.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/results.bin 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/transformed/classes/classes.dex 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/intermediates/compile_library_classes_jar/debug/classes.jar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/intermediates/compile_r_class_jar/debug/R.jar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/intermediates/compile_symbol_list/debug/R.txt 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/intermediates/javac/debug/classes/com/demo/lib/common/widget/FlowLayout.class 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/intermediates/runtime_library_classes_jar/debug/classes.jar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/library-common/build/tmp/compileDebugJavaWithJavac/source-classes-mapping.txt 112 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/.gitignore 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/.metadata 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/README.md 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/analysis_options.yaml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/.gitignore 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/build.gradle 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/debug/AndroidManifest.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/AndroidManifest.xml 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/kotlin/com/example/hanju/MainActivity.kt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/drawable-v21/launch_background.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/drawable/launch_background.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/values-night/styles.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/main/res/values/styles.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/app/src/profile/AndroidManifest.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/build.gradle 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/gradle.properties 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/gradle/wrapper/gradle-wrapper.properties 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/android/settings.gradle 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/.gitignore 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Flutter/AppFrameworkInfo.plist 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Flutter/Debug.xcconfig 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Flutter/Release.xcconfig 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner.xcodeproj/project.pbxproj 484 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner.xcworkspace/contents.xcworkspacedata 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/AppDelegate.swift 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Base.lproj/LaunchScreen.storyboard 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Base.lproj/Main.storyboard 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Info.plist 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/ios/Runner/Runner-Bridging-Header.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/api/http.dart 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/main.dart 219 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/model/common/adinfo_model.dart 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/model/common/http_model.dart 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/model/user/user_info.dart 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/common/browser.dart 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/main/main.dart 321 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/main/mine.dart 539 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/mine/advice.dart 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/mine/advice_submit.dart 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/mine/login.dart 495 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/mine/settings.dart 339 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/widget/base_ui.dart 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/widget/button.dart 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/widget/capture.dart 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/widget/dialog.dart 559 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/widget/nav.dart 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/ui/widget/sos_ui.dart 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/ad_util.dart 610 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/app_util.dart 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/cache_util.dart 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/config_util.dart 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/encrypt_util.dart 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/event_bus_util.dart 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/global.dart 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/jsinterface.dart 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/pageutils.dart 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/permission_util.dart 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/push_util.dart 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/setting_util.dart 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/share_utils.dart 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/string_util.dart 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/ui_constant.dart 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/ui_utils.dart 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/lib/utils/user_util.dart 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/pubspec.lock 691 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/pubspec.yaml 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/web/favicon.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/web/icons/Icon-192.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/web/icons/Icon-512.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/web/icons/Icon-maskable-192.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/web/icons/Icon-maskable-512.png 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/web/index.html 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/flutter/web/manifest.json 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/code/android/app/src/main/java/com/demo/app/utils/Constant.java
@@ -5,6 +5,8 @@
    public final static String HOST = "http://xxx";
    public final static String DOWNLOAD_DIR_NAME = "xxx";
    public final static boolean isDisableProxy = false;
    public static final String USER_AGREEMENT = "http://h5.hanju.goxcw.com/hanju/user_protocol.html";
src/main/resources/code/android/app/src/main/java/com/demo/app/utils/browser/MyJavaInterface.java
@@ -2,6 +2,7 @@
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -16,7 +17,10 @@
import android.widget.TextView;
import android.widget.Toast;
import com.demo.app.utils.Constant;
import com.demo.app.utils.JumpActivityUtil;
import com.demo.lib.common.dialog.DialogUtil;
import com.demo.lib.common.util.ui.LoadingDialogUtil;
import com.demo.library_ec.AlibcTradeUtil;
import com.demo.lib.common.util.Environment;
import com.demo.lib.common.util.common.StringUtils;
@@ -43,12 +47,14 @@
    ImageView iv_right;
    WebView webview;
    private boolean boo = false;
    private Dialog loadingDialog;
    public MyJavaInterface(Activity activity, WebView webview) {
        super(activity);
        mContext = activity;
        this.webview = webview;
        boo = true;
        loadingDialog = LoadingDialogUtil.getLoadingDialog(activity, "");
    }
    public MyJavaInterface(Activity activity, TextView tv_top_bar_middle
@@ -61,6 +67,7 @@
        this.tv_top_bar_right = tv_top_bar_right;
        this.iv_right = iv_right;
        this.webview = webview;
        loadingDialog = LoadingDialogUtil.getLoadingDialog(activity, "");
    }
    @JavascriptInterface
@@ -137,6 +144,28 @@
        AlibcTradeUtil.openAuthLink(mContext, url);
    }
    @JavascriptInterface
    public void showLoading() {
        mContext.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                DialogUtil.show(loadingDialog);
            }
        });
    }
    @JavascriptInterface
    public void hideLoading() {
        mContext.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                DialogUtil.dismiss(loadingDialog);
            }
        });
    }
    // 判断权限集合 是否授权 false授权 true未授权
    public boolean lacksPermissions(String... permissions) {
        for (String permission : permissions) {
@@ -160,8 +189,12 @@
            ActivityCompat.requestPermissions(mContext, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 10023);
        } else {//存储权限已开
            String md5 = MD5Utils.getMD532(url);
            String path = Environment.getExternalStorageDirectory()
                    + "/hanju";
            String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                    + "/" + Constant.DOWNLOAD_DIR_NAME;
            if (!new File(path).exists()) {
                new File(path).mkdirs();
            }
            File file = new File(path + "/" + md5 + ".jpg");
            if (!file.exists()) {
                try {
src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/results.bin
New file
@@ -0,0 +1 @@
o/classes
src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/transformed/classes/classes.dex
Binary files differ
src/main/resources/code/android/library-common/build/intermediates/compile_library_classes_jar/debug/classes.jar
Binary files differ
src/main/resources/code/android/library-common/build/intermediates/compile_r_class_jar/debug/R.jar
Binary files differ
src/main/resources/code/android/library-common/build/intermediates/compile_symbol_list/debug/R.txt
@@ -420,6 +420,13 @@
int attr selectableItemBackground 0x0
int attr selectableItemBackgroundBorderless 0x0
int attr shelfBackground 0x0
int attr shimmer_angle 0x0
int attr shimmer_animation_duration 0x0
int attr shimmer_auto_start 0x0
int attr shimmer_color 0x0
int attr shimmer_gradient_center_color_width 0x0
int attr shimmer_mask_width 0x0
int attr shimmer_reverse_animation 0x0
int attr showAsAction 0x0
int attr showDividers 0x0
int attr showMotionSpec 0x0
@@ -604,6 +611,9 @@
int color bright_foreground_material_light 0x0
int color button_material_dark 0x0
int color button_material_light 0x0
int color by_footer_text_loading 0x0
int color by_skeleton_light_transparent 0x0
int color by_skeleton_shimmer_color 0x0
int color cardview_dark_background 0x0
int color cardview_light_background 0x0
int color cardview_shadow_end_color 0x0
@@ -780,6 +790,11 @@
int dimen abc_text_size_subtitle_material_toolbar 0x0
int dimen abc_text_size_title_material 0x0
int dimen abc_text_size_title_material_toolbar 0x0
int dimen by_load_more_simple_height 0x0
int dimen by_load_more_simple_margin 0x0
int dimen by_progress_width_height 0x0
int dimen by_refresh_simple_height 0x0
int dimen by_refresh_simple_margin 0x0
int dimen cardview_compat_inset_shadow 0x0
int dimen cardview_default_elevation 0x0
int dimen cardview_default_radius 0x0
@@ -1026,6 +1041,8 @@
int drawable btn_radio_off_to_on_mtrl_animation 0x0
int drawable btn_radio_on_mtrl 0x0
int drawable btn_radio_on_to_off_mtrl_animation 0x0
int drawable by_progress_rotate 0x0
int drawable by_refresh_arrow 0x0
int drawable color_progressbar 0x0
int drawable design_bottom_navigation_item_background 0x0
int drawable design_fab_background 0x0
@@ -1188,16 +1205,19 @@
int id glide_custom_view_target_tag 0x0
int id group_divider 0x0
int id gv_emotion 0x0
int id header_content 0x0
int id home 0x0
int id homeAsUp 0x0
int id horizontal 0x0
int id icon 0x0
int id icon_group 0x0
int id id_by_sticky_item 0x0
int id ifRoom 0x0
int id image 0x0
int id info 0x0
int id italic 0x0
int id item_touch_helper_previous_elevation 0x0
int id iv_arrow 0x0
int id labeled 0x0
int id largeLabel 0x0
int id left 0x0
@@ -1205,6 +1225,7 @@
int id line3 0x0
int id listMode 0x0
int id list_item 0x0
int id ll_more_loading 0x0
int id main_content 0x0
int id masked 0x0
int id media_actions 0x0
@@ -1230,6 +1251,7 @@
int id parentPanel 0x0
int id parent_matrix 0x0
int id pause 0x0
int id pb_progress 0x0
int id pin 0x0
int id prev 0x0
int id progress_circular 0x0
@@ -1311,13 +1333,17 @@
int id transition_position 0x0
int id transition_scene_layoutid_cache 0x0
int id transition_transform 0x0
int id tv_more_failed 0x0
int id tv_msg 0x0
int id tv_no_more 0x0
int id tv_refresh_tip 0x0
int id unchecked 0x0
int id uniform 0x0
int id unlabeled 0x0
int id up 0x0
int id useLogo 0x0
int id vertical 0x0
int id view_bottom 0x0
int id view_offset_helper 0x0
int id visible 0x0
int id webview_player 0x0
@@ -1396,6 +1422,8 @@
int layout emotion_grid 0x0
int layout emotion_item 0x0
int layout fragment_webview_video 0x0
int layout layout_by_default_item_skeleton 0x0
int layout layout_by_skeleton_shimmer 0x0
int layout listview_footer 0x0
int layout media_controller 0x0
int layout mtrl_layout_snackbar 0x0
@@ -1418,6 +1446,8 @@
int layout select_dialog_item_material 0x0
int layout select_dialog_multichoice_material 0x0
int layout select_dialog_singlechoice_material 0x0
int layout simple_by_load_more_view 0x0
int layout simple_by_refresh_view 0x0
int layout support_simple_spinner_dropdown_item 0x0
int string abc_action_bar_home_description 0x0
int string abc_action_bar_up_description 0x0
@@ -1461,6 +1491,13 @@
int string app_name 0x0
int string appbar_scrolling_view_behavior 0x0
int string bottom_sheet_behavior 0x0
int string by_footer_load_failed 0x0
int string by_footer_loading 0x0
int string by_footer_no_more 0x0
int string by_header_hint_normal 0x0
int string by_header_hint_release 0x0
int string by_refresh_done 0x0
int string by_refreshing 0x0
int string character_counter_content_description 0x0
int string character_counter_pattern 0x0
int string fab_transformation_scrim_behavior 0x0
@@ -2679,6 +2716,14 @@
int styleable SearchView_voiceIcon 16
int[] styleable ShelvesView { 0x0 }
int styleable ShelvesView_shelfBackground 0
int[] styleable ShimmerLayout { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
int styleable ShimmerLayout_shimmer_angle 0
int styleable ShimmerLayout_shimmer_animation_duration 1
int styleable ShimmerLayout_shimmer_auto_start 2
int styleable ShimmerLayout_shimmer_color 3
int styleable ShimmerLayout_shimmer_gradient_center_color_width 4
int styleable ShimmerLayout_shimmer_mask_width 5
int styleable ShimmerLayout_shimmer_reverse_animation 6
int[] styleable SlidingMenu { 0x0 }
int styleable SlidingMenu_rightPadding 0
int[] styleable Snackbar { 0x0, 0x0 }
src/main/resources/code/android/library-common/build/intermediates/javac/debug/classes/com/demo/lib/common/widget/FlowLayout.class
Binary files differ
src/main/resources/code/android/library-common/build/intermediates/runtime_library_classes_jar/debug/classes.jar
Binary files differ
src/main/resources/code/android/library-common/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt
@@ -421,6 +421,13 @@
attr selectableItemBackground
attr selectableItemBackgroundBorderless
attr shelfBackground
attr shimmer_angle
attr shimmer_animation_duration
attr shimmer_auto_start
attr shimmer_color
attr shimmer_gradient_center_color_width
attr shimmer_mask_width
attr shimmer_reverse_animation
attr showAsAction
attr showDividers
attr showMotionSpec
@@ -605,6 +612,9 @@
color bright_foreground_material_light
color button_material_dark
color button_material_light
color by_footer_text_loading
color by_skeleton_light_transparent
color by_skeleton_shimmer_color
color cardview_dark_background
color cardview_light_background
color cardview_shadow_end_color
@@ -781,6 +791,11 @@
dimen abc_text_size_subtitle_material_toolbar
dimen abc_text_size_title_material
dimen abc_text_size_title_material_toolbar
dimen by_load_more_simple_height
dimen by_load_more_simple_margin
dimen by_progress_width_height
dimen by_refresh_simple_height
dimen by_refresh_simple_margin
dimen cardview_compat_inset_shadow
dimen cardview_default_elevation
dimen cardview_default_radius
@@ -1027,6 +1042,8 @@
drawable btn_radio_off_to_on_mtrl_animation
drawable btn_radio_on_mtrl
drawable btn_radio_on_to_off_mtrl_animation
drawable by_progress_rotate
drawable by_refresh_arrow
drawable color_progressbar
drawable design_bottom_navigation_item_background
drawable design_fab_background
@@ -1189,16 +1206,19 @@
id glide_custom_view_target_tag
id group_divider
id gv_emotion
id header_content
id home
id homeAsUp
id horizontal
id icon
id icon_group
id id_by_sticky_item
id ifRoom
id image
id info
id italic
id item_touch_helper_previous_elevation
id iv_arrow
id labeled
id largeLabel
id left
@@ -1206,6 +1226,7 @@
id line3
id listMode
id list_item
id ll_more_loading
id main_content
id masked
id media_actions
@@ -1231,6 +1252,7 @@
id parentPanel
id parent_matrix
id pause
id pb_progress
id pin
id prev
id progress_circular
@@ -1312,13 +1334,17 @@
id transition_position
id transition_scene_layoutid_cache
id transition_transform
id tv_more_failed
id tv_msg
id tv_no_more
id tv_refresh_tip
id unchecked
id uniform
id unlabeled
id up
id useLogo
id vertical
id view_bottom
id view_offset_helper
id visible
id webview_player
@@ -1397,6 +1423,8 @@
layout emotion_grid
layout emotion_item
layout fragment_webview_video
layout layout_by_default_item_skeleton
layout layout_by_skeleton_shimmer
layout listview_footer
layout media_controller
layout mtrl_layout_snackbar
@@ -1419,6 +1447,8 @@
layout select_dialog_item_material
layout select_dialog_multichoice_material
layout select_dialog_singlechoice_material
layout simple_by_load_more_view
layout simple_by_refresh_view
layout support_simple_spinner_dropdown_item
string abc_action_bar_home_description
string abc_action_bar_up_description
@@ -1462,6 +1492,13 @@
string app_name
string appbar_scrolling_view_behavior
string bottom_sheet_behavior
string by_footer_load_failed
string by_footer_loading
string by_footer_no_more
string by_header_hint_normal
string by_header_hint_release
string by_refresh_done
string by_refreshing
string character_counter_content_description
string character_counter_pattern
string fab_transformation_scrim_behavior
@@ -2104,6 +2141,7 @@
styleable ScrollingViewBehavior_Layout behavior_overlapTop
styleable SearchView android_focusable android_imeOptions android_inputType android_maxWidth closeIcon commitIcon defaultQueryHint goIcon iconifiedByDefault layout queryBackground queryHint searchHintIcon searchIcon submitBackground suggestionRowLayout voiceIcon
styleable ShelvesView shelfBackground
styleable ShimmerLayout shimmer_angle shimmer_animation_duration shimmer_auto_start shimmer_color shimmer_gradient_center_color_width shimmer_mask_width shimmer_reverse_animation
styleable SlidingMenu rightPadding
styleable Snackbar snackbarButtonStyle snackbarStyle
styleable SnackbarLayout android_maxWidth elevation maxActionInlineWidth
src/main/resources/code/android/library-common/build/tmp/compileDebugJavaWithJavac/source-classes-mapping.txt
@@ -28,8 +28,10 @@
 com.demo.lib.common.util.common.ConnectionUtils$3
com/demo/lib/common/DatabaseContext.java
 com.demo.lib.common.DatabaseContext
com/demo/lib/common/util/ui/LoadingDialogUtil.java
 com.demo.lib.common.util.ui.LoadingDialogUtil
com/demo/lib/common/okhttp/request/PostFormRequest.java
 com.demo.lib.common.okhttp.request.PostFormRequest
 com.demo.lib.common.okhttp.request.PostFormRequest$1
 com.demo.lib.common.okhttp.request.PostFormRequest$1$1
com/demo/lib/common/util/FragmentSwitchHelper.java
 com.demo.lib.common.util.FragmentSwitchHelper
com/demo/lib/common/util/device/MobileUtil.java
@@ -48,25 +50,30 @@
 com.demo.lib.common.okhttp.builder.HeadBuilder
com/demo/lib/common/util/common/DimenUtils.java
 com.demo.lib.common.util.common.DimenUtils
com/demo/lib/common/dialog/BottomDialog.java
 com.demo.lib.common.dialog.BottomDialog
com/demo/lib/common/okhttp/utils/L.java
 com.demo.lib.common.okhttp.utils.L
com/demo/lib/common/okhttp/builder/OtherRequestBuilder.java
 com.demo.lib.common.okhttp.builder.OtherRequestBuilder
com/demo/lib/common/widget/ShelfView.java
 com.demo.lib.common.widget.ShelfView
com/demo/lib/common/widget/TagCloudLayout.java
 com.demo.lib.common.widget.TagCloudLayout
 com.demo.lib.common.widget.TagCloudLayout$FlingRunnable
 com.demo.lib.common.widget.TagCloudLayout$OnScrollListener
 com.demo.lib.common.widget.TagCloudLayout$TagView
com/demo/lib/common/util/ManifestDataUtil.java
 com.demo.lib.common.util.ManifestDataUtil
com/demo/lib/common/util/SingleToast.java
 com.demo.lib.common.util.SingleToast
 com.demo.lib.common.util.SingleToast$1
com/demo/lib/common/dialog/SlidingDialog.java
 com.demo.lib.common.dialog.SlidingDialog
com/demo/lib/common/okhttp/utils/Platform.java
 com.demo.lib.common.okhttp.utils.Platform
 com.demo.lib.common.okhttp.utils.Platform$Android
 com.demo.lib.common.okhttp.utils.Platform$Android$MainThreadExecutor
com/demo/lib/common/okhttp/log/LoggerInterceptor.java
 com.demo.lib.common.okhttp.log.LoggerInterceptor
com/demo/lib/common/util/common/SoftKeyboardUtils.java
 com.demo.lib.common.util.common.SoftKeyboardUtils
com/demo/lib/common/emotion/EmotionEditText.java
 com.demo.lib.common.emotion.EmotionEditText
com/demo/lib/common/widget/verticalviewpager/ExtendedWebView.java
 com.demo.lib.common.widget.verticalviewpager.ExtendedWebView
com/demo/lib/common/util/MarketUtils.java
 com.demo.lib.common.util.MarketUtils
com/demo/lib/common/upgrade/Version.java
@@ -75,8 +82,8 @@
 com.demo.lib.common.okhttp.builder.PostStringBuilder
com/demo/lib/common/okhttp/request/RequestCall.java
 com.demo.lib.common.okhttp.request.RequestCall
com/demo/lib/common/drawable/SpotlightDrawable.java
 com.demo.lib.common.drawable.SpotlightDrawable
com/demo/lib/common/util/common/StringUtils.java
 com.demo.lib.common.util.common.StringUtils
com/lcjian/lcjianlibrary/BuildConfig.java
 com.lcjian.lcjianlibrary.BuildConfig
com/demo/lib/common/okhttp/request/PostFileRequest.java
@@ -107,8 +114,8 @@
com/demo/lib/common/util/cache/StrictLineReader.java
 com.demo.lib.common.util.cache.StrictLineReader
 com.demo.lib.common.util.cache.StrictLineReader$1
com/demo/lib/common/emotion/EmotionTextView.java
 com.demo.lib.common.emotion.EmotionTextView
com/demo/lib/common/widget/MyGridView.java
 com.demo.lib.common.widget.MyGridView
com/demo/lib/common/entity/IsSeeking.java
 com.demo.lib.common.entity.IsSeeking
com/demo/lib/common/util/security/MD5Utils.java
@@ -141,17 +148,14 @@
 com.demo.lib.common.okhttp.cookie.store.PersistentCookieStore
com/demo/lib/common/okhttp/builder/PostFileBuilder.java
 com.demo.lib.common.okhttp.builder.PostFileBuilder
com/demo/lib/common/widget/RatioLayout.java
 com.demo.lib.common.widget.RatioLayout
com/demo/lib/common/entity/ClipCopyContent.java
 com.demo.lib.common.entity.ClipCopyContent
com/demo/lib/common/upgrade/UpdateActivity.java
 com.demo.lib.common.upgrade.UpdateActivity
 com.demo.lib.common.upgrade.UpdateActivity$1
 com.demo.lib.common.upgrade.UpdateActivity$2
com/demo/lib/common/emotion/EmotionGridFragment.java
 com.demo.lib.common.emotion.EmotionGridFragment
 com.demo.lib.common.emotion.EmotionGridFragment$1
 com.demo.lib.common.emotion.EmotionGridFragment$EmotionAdapter
 com.demo.lib.common.emotion.EmotionGridFragment$OnEditListener
com/demo/lib/common/util/PermissionsChecker.java
 com.demo.lib.common.util.PermissionsChecker
com/demo/lib/common/DeviceUuidFactory.java
 com.demo.lib.common.DeviceUuidFactory
com/demo/lib/common/widget/myswiperefreshlayout/MySwipeRefreshLayout.java
@@ -188,9 +192,8 @@
com/demo/lib/common/drawable/CrossFadeDrawable.java
 com.demo.lib.common.drawable.CrossFadeDrawable
 com.demo.lib.common.drawable.CrossFadeDrawable$1
com/demo/lib/common/util/RefreshLayout.java
 com.demo.lib.common.util.RefreshLayout
 com.demo.lib.common.util.RefreshLayout$OnLoadListener
com/demo/lib/common/widget/MyViewPager.java
 com.demo.lib.common.widget.MyViewPager
com/demo/lib/common/util/common/SerializeUtils.java
 com.demo.lib.common.util.common.SerializeUtils
com/demo/lib/common/okhttp/callback/StringCallback.java
@@ -303,36 +306,35 @@
 com.demo.lib.common.util.common.IClipboardContentListener
com/demo/lib/common/drawable/FastBitmapDrawable.java
 com.demo.lib.common.drawable.FastBitmapDrawable
com/demo/lib/common/widget/AdaptiveListView.java
 com.demo.lib.common.widget.AdaptiveListView
com/demo/lib/common/content/CursorLoader.java
 com.demo.lib.common.content.CursorLoader
com/demo/lib/common/okhttp/utils/Platform.java
 com.demo.lib.common.okhttp.utils.Platform
 com.demo.lib.common.okhttp.utils.Platform$Android
 com.demo.lib.common.okhttp.utils.Platform$Android$MainThreadExecutor
com/demo/lib/common/widget/MyViewPager.java
 com.demo.lib.common.widget.MyViewPager
com/demo/lib/common/util/common/StringUtils.java
 com.demo.lib.common.util.common.StringUtils
com/demo/lib/common/util/PermissionsChecker.java
 com.demo.lib.common.util.PermissionsChecker
com/demo/lib/common/entity/ClipCopyContent.java
 com.demo.lib.common.entity.ClipCopyContent
com/demo/lib/common/widget/MyGridView.java
 com.demo.lib.common.widget.MyGridView
com/demo/lib/common/okhttp/request/PostStringRequest.java
 com.demo.lib.common.okhttp.request.PostStringRequest
com/demo/lib/common/okhttp/request/PostFormRequest.java
 com.demo.lib.common.okhttp.request.PostFormRequest
 com.demo.lib.common.okhttp.request.PostFormRequest$1
 com.demo.lib.common.okhttp.request.PostFormRequest$1$1
com/demo/lib/common/widget/TagCloudLayout.java
 com.demo.lib.common.widget.TagCloudLayout
 com.demo.lib.common.widget.TagCloudLayout$FlingRunnable
 com.demo.lib.common.widget.TagCloudLayout$OnScrollListener
 com.demo.lib.common.widget.TagCloudLayout$TagView
com/demo/lib/common/widget/verticalviewpager/ExtendedWebView.java
 com.demo.lib.common.widget.verticalviewpager.ExtendedWebView
com/demo/lib/common/okhttp/utils/L.java
 com.demo.lib.common.okhttp.utils.L
com/demo/lib/common/content/CursorLoader.java
 com.demo.lib.common.content.CursorLoader
com/demo/lib/common/dialog/BottomDialog.java
 com.demo.lib.common.dialog.BottomDialog
com/demo/lib/common/emotion/EmotionEditText.java
 com.demo.lib.common.emotion.EmotionEditText
com/demo/lib/common/widget/FlowLayout.java
 com.demo.lib.common.widget.FlowLayout
com/demo/lib/common/widget/ShelfView.java
 com.demo.lib.common.widget.ShelfView
com/demo/lib/common/util/ui/LoadingDialogUtil.java
 com.demo.lib.common.util.ui.LoadingDialogUtil
com/demo/lib/common/widget/AdaptiveListView.java
 com.demo.lib.common.widget.AdaptiveListView
com/demo/lib/common/emotion/EmotionTextView.java
 com.demo.lib.common.emotion.EmotionTextView
com/demo/lib/common/widget/RatioLayout.java
 com.demo.lib.common.widget.RatioLayout
com/demo/lib/common/emotion/EmotionGridFragment.java
 com.demo.lib.common.emotion.EmotionGridFragment
 com.demo.lib.common.emotion.EmotionGridFragment$1
 com.demo.lib.common.emotion.EmotionGridFragment$EmotionAdapter
 com.demo.lib.common.emotion.EmotionGridFragment$OnEditListener
com/demo/lib/common/drawable/SpotlightDrawable.java
 com.demo.lib.common.drawable.SpotlightDrawable
com/demo/lib/common/util/RefreshLayout.java
 com.demo.lib.common.util.RefreshLayout
 com.demo.lib.common.util.RefreshLayout$OnLoadListener
com/demo/lib/common/dialog/SlidingDialog.java
 com.demo.lib.common.dialog.SlidingDialog
src/main/resources/code/flutter/.gitignore
New file
@@ -0,0 +1,46 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
src/main/resources/code/flutter/.metadata
New file
@@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
  revision: 18116933e77adc82f80866c928266a5b4f1ed645
  channel: stable
project_type: app
src/main/resources/code/flutter/README.md
New file
@@ -0,0 +1,16 @@
# hanju
A new Flutter project.
## 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.
src/main/resources/code/flutter/analysis_options.yaml
New file
@@ -0,0 +1,29 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
  # The lint rules applied to this project can be customized in the
  # section below to disable rules from the `package:flutter_lints/flutter.yaml`
  # included above or to enable additional rules. A list of all available lints
  # and their documentation is published at
  # https://dart-lang.github.io/linter/lints/index.html.
  #
  # Instead of disabling a lint rule for the entire project in the
  # section below, it can also be suppressed for a single line of code
  # or a specific dart file by using the `// ignore: name_of_lint` and
  # `// ignore_for_file: name_of_lint` syntax on the line or in the file
  # producing the lint.
  rules:
    # avoid_print: false  # Uncomment to disable the `avoid_print` rule
    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
src/main/resources/code/flutter/android/.gitignore
New file
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
src/main/resources/code/flutter/android/app/build.gradle
New file
@@ -0,0 +1,68 @@
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 30
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }
    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.hanju"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    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
        }
    }
}
flutter {
    source '../..'
}
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
src/main/resources/code/flutter/android/app/src/debug/AndroidManifest.xml
New file
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.hanju">
    <!-- Flutter needs it to communicate with the running application
         to allow setting breakpoints, to provide hot reload, etc.
    -->
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>
src/main/resources/code/flutter/android/app/src/main/AndroidManifest.xml
New file
@@ -0,0 +1,41 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.hanju">
   <application
        android:label="hanju"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <!-- Displays an Android View that continues showing the launch screen
                 Drawable until Flutter paints its first frame, then this splash
                 screen fades out. A splash screen is useful to avoid any visual
                 gap between the end of Android's launch screen and the painting of
                 Flutter's first frame. -->
            <meta-data
              android:name="io.flutter.embedding.android.SplashScreenDrawable"
              android:resource="@drawable/launch_background"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>
src/main/resources/code/flutter/android/app/src/main/kotlin/com/example/hanju/MainActivity.kt
New file
@@ -0,0 +1,6 @@
package com.example.hanju
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
src/main/resources/code/flutter/android/app/src/main/res/drawable-v21/launch_background.xml
New file
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="?android:colorBackground" />
    <!-- You can insert your own image assets here -->
    <!-- <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/launch_image" />
    </item> -->
</layer-list>
src/main/resources/code/flutter/android/app/src/main/res/drawable/launch_background.xml
New file
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/white" />
    <!-- You can insert your own image assets here -->
    <!-- <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/launch_image" />
    </item> -->
</layer-list>
src/main/resources/code/flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
src/main/resources/code/flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
src/main/resources/code/flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
src/main/resources/code/flutter/android/app/src/main/res/values-night/styles.xml
New file
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
    <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
        <!-- Show a splash screen on the activity. Automatically removed when
             Flutter draws its first frame -->
        <item name="android:windowBackground">@drawable/launch_background</item>
    </style>
    <!-- Theme applied to the Android Window as soon as the process has started.
         This theme determines the color of the Android Window while your
         Flutter UI initializes, as well as behind your Flutter UI while its
         running.
         This Theme is only used starting with V2 of Flutter's Android embedding. -->
    <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
        <item name="android:windowBackground">?android:colorBackground</item>
    </style>
</resources>
src/main/resources/code/flutter/android/app/src/main/res/values/styles.xml
New file
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
    <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
        <!-- Show a splash screen on the activity. Automatically removed when
             Flutter draws its first frame -->
        <item name="android:windowBackground">@drawable/launch_background</item>
    </style>
    <!-- Theme applied to the Android Window as soon as the process has started.
         This theme determines the color of the Android Window while your
         Flutter UI initializes, as well as behind your Flutter UI while its
         running.
         This Theme is only used starting with V2 of Flutter's Android embedding. -->
    <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
        <item name="android:windowBackground">?android:colorBackground</item>
    </style>
</resources>
src/main/resources/code/flutter/android/app/src/profile/AndroidManifest.xml
New file
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.hanju">
    <!-- Flutter needs it to communicate with the running application
         to allow setting breakpoints, to provide hot reload, etc.
    -->
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>
src/main/resources/code/flutter/android/build.gradle
New file
@@ -0,0 +1,29 @@
buildscript {
    ext.kotlin_version = '1.3.50'
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
allprojects {
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
    project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
    delete rootProject.buildDir
}
src/main/resources/code/flutter/android/gradle.properties
New file
@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
src/main/resources/code/flutter/android/gradle/wrapper/gradle-wrapper.properties
New file
@@ -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-6.7-all.zip
src/main/resources/code/flutter/android/settings.gradle
New file
@@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
src/main/resources/code/flutter/ios/.gitignore
New file
@@ -0,0 +1,34 @@
**/dgph
*.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/ephemeral/
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
src/main/resources/code/flutter/ios/Flutter/AppFrameworkInfo.plist
New file
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleDevelopmentRegion</key>
  <string>en</string>
  <key>CFBundleExecutable</key>
  <string>App</string>
  <key>CFBundleIdentifier</key>
  <string>io.flutter.flutter.app</string>
  <key>CFBundleInfoDictionaryVersion</key>
  <string>6.0</string>
  <key>CFBundleName</key>
  <string>App</string>
  <key>CFBundlePackageType</key>
  <string>FMWK</string>
  <key>CFBundleShortVersionString</key>
  <string>1.0</string>
  <key>CFBundleSignature</key>
  <string>????</string>
  <key>CFBundleVersion</key>
  <string>1.0</string>
  <key>MinimumOSVersion</key>
  <string>9.0</string>
</dict>
</plist>
src/main/resources/code/flutter/ios/Flutter/Debug.xcconfig
New file
@@ -0,0 +1 @@
#include "Generated.xcconfig"
src/main/resources/code/flutter/ios/Flutter/Release.xcconfig
New file
@@ -0,0 +1 @@
#include "Generated.xcconfig"
src/main/resources/code/flutter/ios/Runner.xcodeproj/project.pbxproj
New file
@@ -0,0 +1,484 @@
// !$*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 = "<group>"; };
        1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
        3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
        74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
        74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
        7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
        9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
        9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
        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 = "<group>"; };
        97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
        97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
        97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* 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 = "<group>";
        };
        97C146E51CF9000F007C117D = {
            isa = PBXGroup;
            children = (
                9740EEB11CF90186004384FC /* Flutter */,
                97C146F01CF9000F007C117D /* Runner */,
                97C146EF1CF9000F007C117D /* Products */,
            );
            sourceTree = "<group>";
        };
        97C146EF1CF9000F007C117D /* Products */ = {
            isa = PBXGroup;
            children = (
                97C146EE1CF9000F007C117D /* Runner.app */,
            );
            name = Products;
            sourceTree = "<group>";
        };
        97C146F01CF9000F007C117D /* Runner */ = {
            isa = PBXGroup;
            children = (
                97C146FA1CF9000F007C117D /* Main.storyboard */,
                97C146FD1CF9000F007C117D /* Assets.xcassets */,
                97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
                97C147021CF9000F007C117D /* Info.plist */,
                1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
                1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
                74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
                74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
            );
            path = Runner;
            sourceTree = "<group>";
        };
/* 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 = 1020;
                ORGANIZATIONNAME = "";
                TargetAttributes = {
                    97C146ED1CF9000F007C117D = {
                        CreatedOnToolsVersion = 7.3.1;
                        LastSwiftMigration = 1100;
                    };
                };
            };
            buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
            compatibilityVersion = "Xcode 9.3";
            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 = "<group>";
        };
        97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
            isa = PBXVariantGroup;
            children = (
                97C147001CF9000F007C117D /* Base */,
            );
            name = LaunchScreen.storyboard;
            sourceTree = "<group>";
        };
/* 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)";
                DEVELOPMENT_TEAM = 98HSDT7AP4;
                ENABLE_BITCODE = NO;
                INFOPLIST_FILE = Runner/Info.plist;
                LD_RUNPATH_SEARCH_PATHS = (
                    "$(inherited)",
                    "@executable_path/Frameworks",
                );
                PRODUCT_BUNDLE_IDENTIFIER = com.flutter.test;
                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_COMPILATION_MODE = wholemodule;
                SWIFT_OPTIMIZATION_LEVEL = "-O";
                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)";
                DEVELOPMENT_TEAM = 98HSDT7AP4;
                ENABLE_BITCODE = NO;
                INFOPLIST_FILE = Runner/Info.plist;
                LD_RUNPATH_SEARCH_PATHS = (
                    "$(inherited)",
                    "@executable_path/Frameworks",
                );
                PRODUCT_BUNDLE_IDENTIFIER = com.flutter.test;
                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)";
                DEVELOPMENT_TEAM = 98HSDT7AP4;
                ENABLE_BITCODE = NO;
                INFOPLIST_FILE = Runner/Info.plist;
                LD_RUNPATH_SEARCH_PATHS = (
                    "$(inherited)",
                    "@executable_path/Frameworks",
                );
                PRODUCT_BUNDLE_IDENTIFIER = com.flutter.test;
                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 */;
}
src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
New file
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:">
   </FileRef>
</Workspace>
src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
New file
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>IDEDidComputeMac32BitWarning</key>
    <true/>
</dict>
</plist>
src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
New file
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PreviewsEnabled</key>
    <false/>
</dict>
</plist>
src/main/resources/code/flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
New file
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "1020"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "97C146ED1CF9000F007C117D"
               BuildableName = "Runner.app"
               BlueprintName = "Runner"
               ReferencedContainer = "container:Runner.xcodeproj">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES">
      <Testables>
      </Testables>
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
            BuildableName = "Runner.app"
            BlueprintName = "Runner"
            ReferencedContainer = "container:Runner.xcodeproj">
         </BuildableReference>
      </MacroExpansion>
      <AdditionalOptions>
      </AdditionalOptions>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
            BuildableName = "Runner.app"
            BlueprintName = "Runner"
            ReferencedContainer = "container:Runner.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Profile"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
            BuildableName = "Runner.app"
            BlueprintName = "Runner"
            ReferencedContainer = "container:Runner.xcodeproj">
         </BuildableReference>
      </BuildableProductRunnable>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>
src/main/resources/code/flutter/ios/Runner.xcworkspace/contents.xcworkspacedata
New file
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "group:Runner.xcodeproj">
   </FileRef>
</Workspace>
src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
New file
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>IDEDidComputeMac32BitWarning</key>
    <true/>
</dict>
</plist>
src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
New file
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PreviewsEnabled</key>
    <false/>
</dict>
</plist>
src/main/resources/code/flutter/ios/Runner/AppDelegate.swift
New file
@@ -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)
  }
}
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
New file
@@ -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"
  }
}
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
New file
@@ -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"
  }
}
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
New file
@@ -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.
src/main/resources/code/flutter/ios/Runner/Base.lproj/LaunchScreen.storyboard
New file
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="EHf-IW-A2E">
            <objects>
                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
                        <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
                            </imageView>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
                            <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
                        </constraints>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="53" y="375"/>
        </scene>
    </scenes>
    <resources>
        <image name="LaunchImage" width="168" height="185"/>
    </resources>
</document>
src/main/resources/code/flutter/ios/Runner/Base.lproj/Main.storyboard
New file
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
    </dependencies>
    <scenes>
        <!--Flutter View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
        </scene>
    </scenes>
</document>
src/main/resources/code/flutter/ios/Runner/Info.plist
New file
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>$(DEVELOPMENT_LANGUAGE)</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>hanju</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>$(FLUTTER_BUILD_NAME)</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>$(FLUTTER_BUILD_NUMBER)</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIMainStoryboardFile</key>
    <string>Main</string>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationPortraitUpsideDown</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
</dict>
</plist>
src/main/resources/code/flutter/ios/Runner/Runner-Bridging-Header.h
New file
@@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"
src/main/resources/code/flutter/lib/api/http.dart
New file
@@ -0,0 +1,269 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:device_info/device_info.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import '../utils/string_util.dart';
import '../utils/user_util.dart';
import '../utils/app_util.dart';
import '../utils/global.dart';
import '../utils/encrypt_util.dart';
import '../ui/widget/dialog.dart';
import '../utils/ui_utils.dart';
import '../model/common/http_model.dart';
typedef OnHttpRequestFinish = void Function(HttpRequestResult result);
typedef OnHttpRequestStart = void Function();
showLoading(BuildContext context) {
  //先丢失焦点
  FocusScope.of(context).unfocus();
  //开启加载框
  DialogUtil.showDialog(context, LoadingDialog(""));
}
dismissDialog(BuildContext context) {
  Navigator.pop(context);
}
class HttpUtil {
  static AndroidDeviceInfo? _androidInfo;
  static IosDeviceInfo? _iosInfo;
  static _getSign(Map<String, dynamic> params) {
    List list = [];
    //签名
    params.forEach((key, value) {
      list.add("$key=$value");
    });
    //排序
    list.sort();
    String signStr = "";
    list.forEach((element) {
      signStr += element + "&";
    });
    signStr += "@#\$^234AB&c&fg&.==888";
    return EncryptUtil.MD5(signStr);
  }
  static Future<Map<String, dynamic>> getBaseParams(
      Map<String, dynamic>? params) async {
    params ??= {};
    if (Platform.isAndroid) {
      if (_androidInfo == null) {
        DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
        _androidInfo = await deviceInfo.androidInfo;
      }
    } else if (Platform.isIOS) {
      if (_iosInfo == null) {
        DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
        _iosInfo = await deviceInfo.iosInfo;
      }
    }
    params["version"] = (await AppUtil.getVersionCode()).toString();
    print("androidInfo:${_androidInfo!.version}");
    //添加附加参数
    params["timestamp"] = DateTime.now().millisecondsSinceEpoch.toString();
    params["platform"] = Platform.isAndroid ? "android" : "ios";
    params["packages"] = "com.dw.zzql";
    if (Platform.isAndroid) {
      if (Global.utdId != null) {
        params["utdId"] = Global.utdId;
      }
      params["osVersion"] = _androidInfo!.version.release;
    } else if (Platform.isIOS) {
      params["device"] = _iosInfo!.identifierForVendor;
    }
    if (Global.channel != null) {
      params["channel"] = Global.channel;
    }
    params["sign"] = _getSign(params);
    return params;
  }
  static Future<HttpRequestResult> baseRequest(
      String api, Map<String, dynamic> params, OnHttpRequestStart? onStart,
      {bool notifyError = false}) async {
    // params ??= {};
    params = await getBaseParams(params);
    var httpClient = HttpClient();
    httpClient.connectionTimeout = const Duration(seconds: 20);
    var uri = Uri(
        scheme: "http",
        host: "api.location.izzql.com",
        path: api,
        port: 8090,
        queryParameters: params);
    // var uri = Uri(
    //     scheme: "http",
    //     host: "192.168.3.122",
    //     path: api,
    //     port: 8082,
    //     queryParameters: params);
    print("uri:$uri");
    if (onStart != null) {
      onStart();
    }
    HttpRequestResult requestResult;
    try {
      HttpClientRequest request = await httpClient.postUrl(uri);
      var response = await request.close();
      if (response.statusCode == HttpStatus.ok) {
        String result = await response.transform(const Utf8Decoder()).join();
        requestResult = HttpRequestResult(true, jsonDecode(result));
      } else {
        requestResult = HttpRequestResult(false, null, msg: "网络请求失败");
      }
    } on TimeoutException catch (_) {
      requestResult = HttpRequestResult(false, null, msg: "网络请求超时");
    } on SocketException catch (_) {
      Fluttertoast.showToast(msg: "网络请求出错");
      requestResult = HttpRequestResult(false, null, msg: "网络请求出错");
    }
    if (notifyError && !requestResult.success) {
      ToastUtil.toast(requestResult.msg!);
    }
    return requestResult;
  }
}
class UserApiUtil {
  ///验证码发送
  static Future<Map<String, dynamic>?> sendSMS(
      BuildContext context, String phone) async {
    var result =
        await HttpUtil.baseRequest("/api/v1/sms/sendSMS", {"phone": phone}, () {
      showLoading(context);
    });
    dismissDialog(context);
    if (result.success) {
      return result.data;
    }
    return null;
  }
  static Future<Map<String, dynamic>?> uploadPushRegId(
      BuildContext context, String regId) async {
    var uid = await UserUtil.getUid();
    var params = {"regId": regId};
    if (uid != null) {
      params["uid"] = uid.toString();
    }
    var result = await HttpUtil.baseRequest(
        "/api/v1/user/uploadPushRegId", params, () {});
    if (result.success) {
      return result.data;
    }
    return null;
  }
  ///登录
  static Future<Map<String, dynamic>?> login(
      BuildContext context, String phone, String vcode, String token) async {
    Map<String, dynamic> params = {};
    params["phone"] = phone;
    if (!StringUtil.isNullOrEmpty(vcode)) {
      params["vcode"] = vcode;
    }
    if (!StringUtil.isNullOrEmpty(token)) {
      params["token"] = token;
    }
    var result =
        await HttpUtil.baseRequest("/api/v1/user/loginPhone", params, () {
      showLoading(context);
    }, notifyError: true);
    dismissDialog(context);
    if (result.success) {
      return result.data;
    }
    return null;
  }
  ///获取用户信息
  static Future<Map<String, dynamic>?> getUserInfo(
      BuildContext context, int uid) async {
    Map<String, dynamic> params = {};
    params["uid"] = uid.toString();
    var result =
        await HttpUtil.baseRequest("/api/v1/user/getUserInfo", params, () {});
    if (result.success) {
      return result.data;
    }
    return null;
  }
  ///退出登录
  static Future<Map<String, dynamic>?> logout(
      BuildContext context, int? uid) async {
    Map<String, dynamic> params = {};
    params["uid"] = uid.toString();
    var result =
        await HttpUtil.baseRequest("/api/v1/user/logout", params, () {});
    if (result.success) {
      return result.data;
    }
    return null;
  }
}
class FeedBackApiUtil {
  ///查阅向我求救的SOS
  static Future<Map<String, dynamic>?> advice(
      BuildContext context, String? type, String content) async {
    var uid = await UserUtil.getUid();
    Map<String, dynamic> params = {};
    if (uid != null) {
      params["uid"] = uid.toString();
    }
    if (type != null) {
      params["type"] = type;
    }
    params["content"] = content;
    var result =
        await HttpUtil.baseRequest("/api/v1/feedback/advice", params, () {
      showLoading(context);
    }, notifyError: true);
    dismissDialog(context);
    if (result.success) {
      return result.data;
    }
    return null;
  }
}
class ConfigApiUtil {
  ///查阅向我求救的SOS
  static Future<Map<String, dynamic>?> getConfig() async {
    var result = await HttpUtil.baseRequest(
        "/api/v1/config/getConfig", {}, () {},
        notifyError: true);
    if (result.success) {
      return result.data;
    }
    return null;
  }
}
src/main/resources/code/flutter/lib/main.dart
New file
@@ -0,0 +1,219 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import './api/http.dart';
import './utils/ad_util.dart';
import './utils/app_util.dart';
import './utils/config_util.dart';
import './utils/pageutils.dart';
import './utils/permission_util.dart';
import './utils/ui_utils.dart';
import './utils/user_util.dart';
import 'package:permission_handler/permission_handler.dart';
import 'ui/main/main.dart';
import 'ui/widget/dialog.dart';
import 'utils/ui_constant.dart';
import 'utils/global.dart';
void main() {
  if (Platform.isAndroid) {
    SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
      systemNavigationBarColor: Colors.white,
      systemNavigationBarDividerColor: null,
      systemNavigationBarIconBrightness: Brightness.light,
      statusBarIconBrightness: Brightness.dark,
      statusBarBrightness: Brightness.light,
    ));
  }
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: Constant.APP_NAME,
        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.
            primaryColor: const Color(0xFFFFFFFF)),
        home: SplashPage(title: ''),
        navigatorKey: navigatorKey);
  }
}
class SplashPage extends StatefulWidget {
  SplashPage({Key? key, required this.title}) : super(key: key);
  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.
  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".
  final String title;
  @override
  _SplashPageState createState() => _SplashPageState();
}
class _SplashPageState extends State<SplashPage>
    with SingleTickerProviderStateMixin {
  int selectIndex = 1;
  Widget? _splash;
  @override
  void initState() {
    super.initState();
  }
  bool _jumpToMain = false;
  void init() async {
    //请求配置信息
    var value = await ConfigApiUtil.getConfig();
    if (value != null) {
      ConfigUtil.saveConfig(value["data"]);
    }
    await AppUtil.initApp(context);
    Widget splash = AdUtil.loadSplash(
        await AdUtil.getAdInfo(AdPosition.splash),
        MediaQuery.of(context).size.width,
        MediaQuery.of(context).size.height - 94, (success, msg) {
      if (_jumpToMain == true) {
        return;
      }
      _jumpToMain = true;
      if (success) {
        NavigatorUtil.navigateToNextPageWithFinish(context,
            CupertinoPageRoute(builder: (context) {
          return MainPage(title: "");
        }));
      } else {
        Future.delayed(const Duration(seconds: 2), () {
          NavigatorUtil.navigateToNextPageWithFinish(context,
              CupertinoPageRoute(builder: (context) {
            return MainPage(title: "");
          }));
        });
      }
    });
    setState(() {
      _splash = splash;
    });
  }
  Future requestPermission() async {
    await PermissionUtil.openPermission(Permission.phone);
    // await PermissionUtil.openPermission(PermissionUtil.getLocationPermission());
    return;
  }
  @override
  Widget build(BuildContext context) {
    UserUtil.isAgreeProtocol().then((value) {
      if (!value) {
        //弹出用户协议框
        String content = "尊敬的用户:<br>" +
            "感谢您对定位App一直以来的信任!<br>" +
            "我们非常重视保护您的个人信息和隐私。在您使用我们的软件前,为了更好的保障您的权利,请务必阅读<a href='${Constant.PROTOCOL_URL}'>《用户协议》</a>和<a href='${Constant.PRIVACY_URL}'>《隐私政策》</a>,您同意并接受所有条款后,才能使用我们软件。若您注册成为本软件会员或接受好友的邀请即表明您允许向本软件中的好友提供您的地理位置和轨迹等信息。为确保软件正常运行我们需要获得,尤其是:<br>" +
            "1、我们对您的个人信息(包括但不限于<b style='color:red'>设备MAC地址、IMEI/Android ID、位置信息</b>等信息)的收集/保存/使用/对外提供/保护等规则条款,以及您的用户权利等条款;<br>" +
            "2、约定我们的限制责任、免责条款;<br>" +
            "3、其他以加粗或斜体字进行标识的重要条款。<br>" +
            "4、特别申明:本软件定位守护等功能需双方都下载本软件并同意授权后才可正常使用,不涉及侵犯个人隐私问题。获取地理信息必须在用户双方知情并同意的情况下进行,本软件仅限用于家庭/亲友/熟人/朋友间使用。<br>" +
            "如您对协议有任何疑虑,可通过电子邮箱:dw365@foxmail.com 向我们询问,我们将为您竭诚解答。您点击“同意并继续”的行为代表您已阅读完毕并接受以上协议全部条款。如您同意以上协议内容,请您点击“同意并继续”,开始使用本软件。";
        DialogUtil.showDialog(
            context,
            NotifyDialog("用户协议&隐私政策", content, () {
              SystemNavigator.pop();
            }, () {
              UserUtil.setAgreeProtocol().then((value) {
                if (value) {
                  //弹出权限框
                  DialogUtil.showDialog(context, PermissionNotifyDialog(() {
                    Navigator.of(context).pop();
                    requestPermission().then((value) {
                      init();
                    });
                  }));
                } else {}
              });
            },
                richText: true,
                height: 400,
                cancelName: "不同意",
                sureName: "同意并继续"));
      } else {
        //已经同意了
        init();
      }
    });
    return WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: Scaffold(
            backgroundColor: Colors.white,
            body: Flex(
              direction: Axis.vertical,
              children: [
                Expanded(
                    child: Stack(children: [
                  Container(
                    alignment: Alignment.center,
                    padding: const EdgeInsets.all(72),
                    color: Colors.white,
                    child: Image.asset("assets/images/ic_splash.png"),
                  ),
                  _splash != null ? _splash! : Container()
                ])),
                Container(
                  alignment: Alignment.center,
                  color: const Color(0xFFF8F8F8),
                  height: 94,
                  child: Flex(
                    direction: Axis.vertical,
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: const [
                      Text(
                        Constant.APP_NAME,
                        style:
                            TextStyle(color: Color(0xFF03B5FF), fontSize: 23),
                      ),
                      SizedBox(
                        height: 15,
                      ),
                      Text(
                        "腾讯云提供网络服务",
                        style: TextStyle(color: Color(0xFF999999), fontSize: 9),
                      ),
                    ],
                  ),
                )
              ],
            )));
  }
}
src/main/resources/code/flutter/lib/model/common/adinfo_model.dart
New file
@@ -0,0 +1,29 @@
/// type : "csj"
/// pid : "123456"
class AdinfoModel {
  AdinfoModel({
      String? type,
      String? pid,}){
    _type = type;
    _pid = pid;
}
  AdinfoModel.fromJson(dynamic json) {
    _type = json['type'];
    _pid = json['pid'];
  }
  String? _type;
  String? _pid;
  String? get type => _type;
  String? get pid => _pid;
  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['type'] = _type;
    map['pid'] = _pid;
    return map;
  }
}
src/main/resources/code/flutter/lib/model/common/http_model.dart
New file
@@ -0,0 +1,16 @@
import '../../api/http.dart';
class HttpRequestResult {
  final Map<String, dynamic>? data;
  final bool success;
  final String? msg;
  HttpRequestResult(this.success, this.data, {this.msg});
}
class HttpRequestListener {
  OnHttpRequestFinish? onFinish;
  OnHttpRequestStart? onStart;
  HttpRequestListener({this.onStart, this.onFinish});
}
src/main/resources/code/flutter/lib/model/user/user_info.dart
New file
@@ -0,0 +1,44 @@
///用户信息
class UserInfo {
  UserInfo(
      {int? id,
      String? nickName,
      String? portrait,
      int? vipExpireTime,
      bool? needAlwaysLocation}) {
    _id = id;
    _nickName = nickName;
    _portrait = portrait;
    _vipExpireTime = vipExpireTime;
  }
  UserInfo.fromJson(dynamic json) {
    _id = int.parse(json['id'].toString());
    _nickName = json['nickName'];
    _portrait = json['portrait'];
    _vipExpireTime = json['vipExpireTime'];
  }
  int? _id;
  String? _nickName;
  String? _portrait;
  int? _vipExpireTime;
  int? get id => _id;
  String? get nickName => _nickName;
  String? get portrait => _portrait;
  int? get vipExpireTime => _vipExpireTime;
  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['id'] = _id;
    map['nickName'] = _nickName;
    map['portrait'] = _portrait;
    map['vipExpireTime'] = _vipExpireTime;
    return map;
  }
}
src/main/resources/code/flutter/lib/ui/common/browser.dart
New file
@@ -0,0 +1,134 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webview_flutter/webview_flutter.dart';
import '../../ui/widget/nav.dart';
import '../../utils/jsinterface.dart';
class BrowserPage extends StatefulWidget {
  BrowserPage({Key? key, required this.title, required this.url})
      : super(key: key);
  final String title;
  final String url;
  @override
  _BrowserPageState createState() => _BrowserPageState(title, url);
}
class _BrowserPageState extends State<BrowserPage>
    with SingleTickerProviderStateMixin {
  String title = "";
  String? url;
  double progress = 0;
  _BrowserPageState(this.title, this.url);
  @override
  void initState() {
    super.initState();
    if (Platform.isAndroid) {
      WebView.platform = SurfaceAndroidWebView();
    }
  }
  WebViewController? _webViewController;
  _back() {
    if (_webViewController == null) {
      Navigator.of(context).pop();
    } else {
      _webViewController!.canGoBack().then((value) {
        if (value) {
          _webViewController!.goBack();
        } else {
          Navigator.of(context).pop();
        }
      });
    }
  }
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
        onWillPop: () async {
          _back();
          return false;
        },
        child: Scaffold(
            backgroundColor: Colors.white,
            body: Flex(
              direction: Axis.vertical,
              children: [
                TopNavBar(
                  title: title,
                  back: () {
                    _back();
                  },
                  rightIcon: Image.asset(
                    "assets/imgs/common/icon_refresh.png",
                    width: 22,
                  ),
                  rightClick: (){
                    if(_webViewController!=null){
                      _webViewController!.reload();
                    }
                  },
                ),
                SizedBox(
                  height: 1,
                  child: LinearProgressIndicator(
                    backgroundColor: Colors.white,
                    valueColor: const AlwaysStoppedAnimation(Color(0xFF0E96FF)),
                    value: progress,
                  ),
                ),
                Expanded(
                    child: WebView(
                  //http://192.168.3.122:8848/test/JsTest.html
                  initialUrl: url,
                  onWebViewCreated: (WebViewController webViewController) {
                    _webViewController = webViewController;
                  },
                  javascriptMode: JavascriptMode.unrestricted,
                  javascriptChannels:
                      JavascriptInterface(context, _webViewController)
                          .getInterfaces(),
                  navigationDelegate: (NavigationRequest request) {
                    print("链接:${request.url}");
                    if (!request.url.startsWith("http")) {
                      launch(request.url);
                      return NavigationDecision.prevent;
                    }
                    return NavigationDecision.navigate;
                  },
                  onPageStarted: (url) {
                    print("process:onPageStarted-$url");
                  },
                  onPageFinished: (url) {
                    print("process:onPageFinished-$url");
                    _webViewController!.getTitle().then((value) {
                      if (value != null) {
                        setState(() {
                          title = value;
                        });
                      }
                    });
                  },
                  onProgress: (int process) {
                    print("process:$process");
                    setState(() {
                      if (process == 100) {
                        progress = 0;
                      } else {
                        progress = process / 100.0;
                      }
                    });
                  },
                ))
              ],
            )));
  }
}
src/main/resources/code/flutter/lib/ui/main/main.dart
New file
@@ -0,0 +1,321 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../api/http.dart';
import '../../ui/widget/dialog.dart';
import '../../utils/ad_util.dart';
import '../../utils/event_bus_util.dart';
import '../../utils/pageutils.dart';
import '../../utils/ui_constant.dart';
import '../../utils/ui_utils.dart';
import '../../utils/user_util.dart';
import 'mine.dart';
void main() {
  if (Platform.isAndroid) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
      systemNavigationBarColor: Color(0xFF000000),
      systemNavigationBarDividerColor: null,
      systemNavigationBarIconBrightness: Brightness.light,
      statusBarIconBrightness: Brightness.dark,
      statusBarBrightness: Brightness.light,
    ));
  }
  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.
          primaryColor: Color(0xFFFFFFFF)),
      home: MainPage(title: ''),
    );
  }
}
class MainPage extends StatefulWidget {
  MainPage({Key? key, required this.title}) : super(key: key);
  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.
  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".
  final String title;
  @override
  _MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage>
    with SingleTickerProviderStateMixin {
  int selectIndex = 1;
  List<Widget> _pages = <Widget>[];
  TabController? _tabController;
  @override
  void initState() {
    _pages
      // ..add(KeepAliveWrapper(child: MainTravelPage()))
      // ..add(KeepAliveWrapper(child: LocationPage(title: "定位")))
      ..add(KeepAliveWrapper(child: MinePage(title: "我的")));
    _tabController =
        TabController(length: _pages.length, initialIndex: 1, vsync: this);
    super.initState();
    Timer(const Duration(seconds: 1), () {
      AdUtil.getAdInfo(AdPosition.homeInterstitial).then((value) {
        AdUtil.loadInterstitial(value, (success, msg) {});
      });
    });
    UserUtil.updateUserInfo(context);
  }
  int lastCenterClick = 0;
  //设置选中的导航栏
  void setSelectIndex(int i) {
    if (i == selectIndex) {
      if (selectIndex == 1) {
        if (DateTime.now().millisecondsSinceEpoch - lastCenterClick < 400) {
          print("双击");
        } else {
          //单击
          Future.delayed(const Duration(milliseconds: 400), () {
            if (DateTime.now().millisecondsSinceEpoch - lastCenterClick <
                400) {
              return;
            }
            print("单击");
          });
        }
        lastCenterClick = DateTime.now().millisecondsSinceEpoch;
      }
      return;
    }
    setState(() {
      selectIndex = i;
    });
    print("setSelectIndex");
    _tabController!.animateTo(i);
  }
  int lastBack = 0;
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
        onWillPop: () async {
          if (DateTime.now().millisecondsSinceEpoch - lastBack > 1000 * 5) {
            lastBack = DateTime.now().millisecondsSinceEpoch;
            ToastUtil.toast("再按一次退出应用");
            return false;
          } else {
            return true;
          }
        },
        child: Scaffold(
          backgroundColor: Colors.white,
          resizeToAvoidBottomInset: false,
          body: Container(
            child: Stack(
              children: [
                //内容栏
                Container(
                  color: Colors.white,
                  child: Flex(
                    direction: Axis.vertical,
                    children: [
                      Expanded(
                          child: TabBarView(
                        controller: _tabController,
                        children: _pages,
                        physics: const NeverScrollableScrollPhysics(),
                      )),
                      Container(
                        height: 60,
                      )
                    ],
                  ),
                ),
                //底部导航栏
                Positioned(
                    bottom: 0,
                    child: Container(
                        child: Stack(
                      alignment: Alignment.bottomCenter,
                      children: [
                        Container(
                          height: 60,
                          width: MediaQuery.of(context).size.width,
                          alignment: Alignment.center,
                          decoration:
                              BoxDecoration(color: Colors.white, boxShadow: [
                            BoxShadow(
                              blurRadius: 10,
                              spreadRadius: 1,
                              color: Color(0x4D0E96FF),
                            )
                          ]),
                          child: Flex(
                            direction: Axis.horizontal,
                            children: [
                              Expanded(
                                  child: getNavItem(
                                      icon: Image.asset(
                                        "assets/imgs/main/icon_main_nav_history.png",
                                        width: 31,
                                      ),
                                      iconHighlight: Image.asset(
                                        "assets/imgs/main/icon_main_nav_history_highlight.png",
                                        width: 31,
                                      ),
                                      text: "轨迹",
                                      index: 0)),
                              Container(
                                width: 54,
                              ),
                              Expanded(
                                  child: getNavItem(
                                      icon: Image.asset(
                                          "assets/imgs/main/icon_main_nav_mine.png",
                                          width: 31),
                                      iconHighlight: Image.asset(
                                          "assets/imgs/main/icon_main_nav_mine_highlight.png",
                                          width: 31),
                                      text: "我的",
                                      index: 2)),
                            ],
                          ),
                        ),
                        Positioned(
                          child: Container(
                            height: 72,
                            width: 72,
                            decoration: BoxDecoration(
                                color: Colors.white,
                                borderRadius: BorderRadius.circular(36),
                                boxShadow: [
                                  BoxShadow(
                                      blurRadius: 10,
                                      spreadRadius: 1,
                                      color: Color(0x4D0E96FF))
                                ]),
                          ),
                        ),
                        Container(
                          height: 60,
                          width: 100,
                          color: Colors.white,
                        ),
                        Container(
                          height: 72,
                          width: 72,
                          alignment: Alignment.center,
                          child: getNavLocationItem(),
                        )
                      ],
                    )))
              ],
            ),
          ),
        ));
  }
  Widget getNavItem(
      {required Image icon,
      required Image iconHighlight,
      required String text,
      required int index}) {
    return Container(
      alignment: Alignment.center,
      child: InkWell(
        onTap: () {
          setSelectIndex(index);
        },
        child: Flex(
          mainAxisAlignment: MainAxisAlignment.center,
          direction: Axis.horizontal,
          children: [
            selectIndex == index ? iconHighlight : icon,
            Text(
              text,
              style: TextStyle(
                  fontSize: 15,
                  color: selectIndex == index
                      ? ColorConstant.theme
                      : Color(0xFF9DAAB3)),
            )
          ],
        ),
      ),
    );
  }
  Widget getNavLocationItem() {
    return InkWell(
        onTap: () {
          setSelectIndex(1);
        },
        child: Container(
          width: 54,
          height: 54,
          decoration: BoxDecoration(
              color: selectIndex == 1 ? ColorConstant.theme : Color(0xFF9DAAB3),
              borderRadius: BorderRadius.circular(27),
              boxShadow: selectIndex == 1
                  ? [
                      BoxShadow(
                          blurRadius: 3,
                          spreadRadius: 2,
                          color: Color(0x4D0E96FF))
                    ]
                  : []),
          child: Flex(
            direction: Axis.vertical,
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Image.asset(
                "assets/imgs/main/icon_main_nav_location.png",
                height: 25,
              ),
              Container(
                height: 3,
              ),
              const Text(
                "定位",
                style: TextStyle(color: Colors.white, fontSize: 9),
              )
            ],
          ),
        ));
  }
}
src/main/resources/code/flutter/lib/ui/main/mine.dart
New file
@@ -0,0 +1,539 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../ui/mine/settings.dart';
import '../../ui/mine/login.dart';
import '../../ui/mine/advice.dart';
import '../../api/http.dart';
import '../../model/user/user_info.dart';
import '../../ui/common/browser.dart';
import '../../utils/ad_util.dart';
import '../../utils/config_util.dart';
import '../../utils/pageutils.dart';
import '../../utils/string_util.dart';
import '../../utils/ui_constant.dart';
import '../../utils/ui_utils.dart';
import '../../utils/user_util.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.
          primaryColor: Color.fromARGB(255, 150, 150, 150)),
      home: MinePage(title: ''),
    );
  }
}
class MinePage extends StatefulWidget {
  MinePage({Key? key, required this.title}) : super(key: key);
  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.
  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".
  final String title;
  @override
  _MinePageState createState() => _MinePageState();
}
class _MinePageState extends State<MinePage>
    with AutomaticKeepAliveClientMixin {
  UserInfo? userInfo = null;
  bool isLogin = false;
  bool isVIP = false;
  List<Widget> list = [];
  Widget? adView;
  bool adDeleted = false;
  final List<Functions> data = [
    Functions("assets/imgs/mine/icon_mine_permission.png", "权限设置",
        "permission", false),
  ];
  void _onClick(Functions function) async {
    if (function.needLogin) {
      bool login = await UserUtil.isLogin();
      if (!login) {
        NavigatorUtil.navigateToNextPage(context, LoginPage(title: ""), (data) {
          _getUserInfo();
        });
        return;
      }
    }
    int? uid = await UserUtil.getUid();
    switch (function.key) {
      case "kefu":
        ConfigUtil.getConfig(ConfigKey.kefu).then((value) {
          if (!StringUtil.isNullOrEmpty(value)) {
            NavigatorUtil.navigateToNextPage(
                context, BrowserPage(title: "在线客服", url: value!), (data) {});
          }
        });
        break;
      case "advice":
        NavigatorUtil.navigateToNextPage(
            context, AdvicePage(title: ""), (data) {});
        break;
      case "protocol":
        NavigatorUtil.navigateToNextPage(
            context,
            BrowserPage(
              title: "用户协议",
              url: Constant.PROTOCOL_URL,
            ),
            (data) {});
        break;
      case "privacy":
        NavigatorUtil.navigateToNextPage(
            context,
            BrowserPage(
              title: "隐私政策",
              url: Constant.PRIVACY_URL,
            ),
            (data) {});
        break;
      case "setting":
        NavigatorUtil.navigateToNextPage(context, SettingPage(title: ""),
            (data) {
          _getUserInfo();
        });
        break;
    }
  }
  @override
  void initState() {
    data.forEach((item) {
      list.add(InkWell(
        child: Column(
          children: [
            Image.asset(item.icon, height: 31),
            Container(
                child: Text(
                  item.name,
                  style: new TextStyle(color: ColorConstant.theme),
                ),
                margin: const EdgeInsets.fromLTRB(0, 13, 0, 0))
          ],
        ),
        onTap: () {
          _onClick(item);
        },
      ));
    });
    //获取用户信息
    _getUserInfo();
    super.initState();
  }
  void _login() {
    NavigatorUtil.navigateToNextPage(context, LoginPage(title: ""), (data) {
      _getUserInfo();
    });
  }
  void _loadAd() async {
    if (adView != null) {
      return;
    }
    if (adDeleted) {
      return;
    }
    Widget? ad = AdUtil.loadExpress(
        await AdUtil.getAdInfo(AdPosition.mineExpress),
        MediaQuery.of(context).size.width - 20,
        200, (success, msg) {
      adDeleted = true;
      setState(() {
        adView = null;
      });
    });
    setState(() {
      adView = ad;
    });
  }
  void _getUserInfo() async {
    var user = await UserUtil.getUserInfo();
    if (user == null) {
      setState(() {
        isLogin = false;
        userInfo = null;
      });
      return;
    }
    setState(() {
      isLogin = true;
      userInfo = user;
    });
    Map<String, dynamic>? result =
        await UserApiUtil.getUserInfo(context, user.id!);
    var code = result!["code"];
    if (code == 0) {
      UserInfo user = UserInfo.fromJson(result["data"]);
      //保存用户信息
      UserUtil.setUserInfo(user);
      setState(() {
        userInfo = user;
        if (userInfo != null &&
            userInfo!.vipExpireTime != null &&
            userInfo!.vipExpireTime! > DateTime.now().millisecondsSinceEpoch) {
          isVIP = true;
        } else {
          isVIP = false;
        }
      });
    } else if (code == 80001) {
      //账号被封禁
      setState(() {
        isLogin = false;
      });
      ToastUtil.toast("账号已被封禁");
      await UserUtil.logout();
    } else if (code == 80002) {
      //账号被删除
      setState(() {
        isLogin = false;
      });
      ToastUtil.toast("账号已被删除");
      await UserUtil.logout();
    }
  }
  Widget getLoginContentView() {
    if (isLogin) {
      return getUserInfoWidget();
    } else {
      return getLoginBtnWidget();
    }
  }
  Widget getLoginBtnWidget() {
    return Expanded(
        child: InkWell(
      onTap: () {
        _login();
      },
      child: Container(
        margin: const EdgeInsets.fromLTRB(10, 0, 10, 0),
        height: 38,
        alignment: Alignment.center,
        child: const Text(
          "登录/注册",
          style: TextStyle(color: Colors.white, fontSize: 15),
        ),
        decoration: const BoxDecoration(
            color: Color(0xFF0E96FF),
            borderRadius: BorderRadius.all(Radius.elliptical(10, 10))),
      ),
    ));
  }
  Widget getUserInfoWidget() {
    return Container(
      height: 50,
      padding: EdgeInsets.zero,
      margin: const EdgeInsets.fromLTRB(10, 0, 0, 0),
      alignment: Alignment.topLeft,
      child: Flex(
        direction: Axis.vertical,
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          Text(
            userInfo!.nickName!,
            style: const TextStyle(color: Color(0xFF40C7FF), fontSize: 18),
          ),
          Text(
            "ID:" + userInfo!.id!.toString(),
            style: const TextStyle(color: Color(0xFF40C7FF), fontSize: 12),
          ),
        ],
      ),
    );
  }
  Widget _getVIPLeftTime() {
    List<TextSpan> spanList = [const TextSpan(text: '剩余')];
    if (userInfo != null && userInfo!.vipExpireTime != null) {
      int leftTime =
          userInfo!.vipExpireTime! - DateTime.now().millisecondsSinceEpoch;
      leftTime = leftTime ~/ 1000;
      if (leftTime >= 60 * 60 * 24) {
        spanList.add(TextSpan(
            text: '${leftTime ~/ (60 * 60 * 24)}',
            style: const TextStyle(fontWeight: FontWeight.bold)));
        spanList.add(const TextSpan(text: '天到期'));
      } else if (leftTime >= 60 * 60) {
        spanList.add(TextSpan(
            text: '${leftTime ~/ (60 * 60)}',
            style: const TextStyle(fontWeight: FontWeight.bold)));
        spanList.add(const TextSpan(text: '小时到期'));
      } else {
        spanList.add(TextSpan(
            text: '${leftTime ~/ (60)}',
            style: const TextStyle(fontWeight: FontWeight.bold)));
        spanList.add(const TextSpan(text: '分钟到期'));
      }
    }
    return Text.rich(TextSpan(
      children: spanList,
      style: const TextStyle(color: Colors.white, fontSize: 17.5),
    ));
  }
  List<Widget> getVIPContent() {
    List<Widget> list = [];
    list.add(Image.asset(
      "assets/imgs/mine/icon_vip.png",
      width: 44,
    ));
    if (isVIP&&userInfo!=null) {
      list.add(Container(
          margin: const EdgeInsets.fromLTRB(6, 0, 0, 0),
          child: _getVIPLeftTime()));
    } else {
      list.add(Container(
        margin: const EdgeInsets.fromLTRB(6, 0, 0, 0),
        child: Image.asset(
          "assets/imgs/mine/label_vip.png",
          height: 20,
        ),
      ));
    }
    return list;
  }
  @override
  Widget build(BuildContext context) {
    _loadAd();
    return Scaffold(
        backgroundColor: Colors.white,
        body: SingleChildScrollView(
            child: Column(
          children: [
            Container(
              decoration: const BoxDecoration(
                  image: DecorationImage(
                      image:
                          AssetImage("assets/imgs/mine/ic_mine_top_bg.png"),
                      fit: BoxFit.cover)),
              height: 350,
              width: 400,
              padding: const EdgeInsets.all(10),
              child: Column(
                children: [
                  //登录与用户信息
                  Container(
                      margin: EdgeInsets.fromLTRB(0, 105, 0, 0),
                      padding: EdgeInsets.all(15),
                      alignment: Alignment.centerLeft,
                      child: Container(
                          height: 50,
                          child: Flex(
                            direction: Axis.horizontal,
                            children: [
                              Image.asset(
                                "assets/imgs/mine/icon_mine_default_portrait.png",
                                width: 50,
                              ),
                              //登录按钮
                              getLoginContentView(),
                              //信息
                            ],
                          )),
                      height: 105,
                      decoration: const BoxDecoration(
                          color: Colors.white,
                          borderRadius:
                              BorderRadius.all(Radius.elliptical(10, 10)))),
                  //会员
                  Container(
                      margin: EdgeInsets.fromLTRB(0, 10, 0, 0),
                      height: 105,
                      width: 400,
                      child: Stack(
                        children: [
                          Container(
                            padding: const EdgeInsets.fromLTRB(18.5, 0, 0, 0),
                            child: Flex(
                              direction: Axis.vertical,
                              mainAxisAlignment: MainAxisAlignment.center,
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Flex(
                                  direction: Axis.horizontal,
                                  crossAxisAlignment: CrossAxisAlignment.center,
                                  children: getVIPContent(),
                                ),
                                Container(
                                  margin: const EdgeInsets.fromLTRB(0, 8, 0, 0),
                                  child: const Text(
                                    "定位守护亲友,黑科技保驾护航",
                                    style: TextStyle(
                                        fontSize: 15, color: Colors.white),
                                  ),
                                )
                              ],
                            ),
                          ),
                          Positioned(
                              right: 0,
                              top: 17,
                              child: InkWell(
                                  onTap: () {
                                    //查看详情或开通
                                    print(isVIP ? "查看详情" : "开通会员");
                                    UserUtil.isLogin().then((value) {
                                      if (!value) {
                                        NavigatorUtil.navigateToNextPage(
                                            context, LoginPage(title: ""),
                                            (data) {
                                          _getUserInfo();
                                        });
                                      }
                                    });
                                  },
                                  child: InkWell(
                                      onTap: () {
                                        UserUtil.isLogin().then((value) {
                                          if (!value) {
                                            NavigatorUtil.navigateToNextPage(
                                                context, LoginPage(title: ""),
                                                (data) {
                                              _getUserInfo();
                                            });
                                            return;
                                          }
                                          ConfigUtil.getConfig(
                                                  ConfigKey.vipLink)
                                              .then((value) {
                                            if (!StringUtil.isNullOrEmpty(
                                                value)) {
                                              NavigatorUtil.navigateToNextPage(
                                                  context,
                                                  BrowserPage(
                                                      title: "会员",
                                                      url: value!), (data) {
                                                _getUserInfo();
                                              });
                                            }
                                          });
                                        });
                                      },
                                      child: Container(
                                          width: 99,
                                          height: 26,
                                          alignment: Alignment.center,
                                          child: Text(
                                            isVIP ? "查看详情" : "立即开通",
                                            style: const TextStyle(
                                                color: Color(0xFFD4A880)),
                                          ),
                                          decoration: const BoxDecoration(
                                            color: Color(0xFFFAEAB9),
                                            borderRadius: BorderRadius.only(
                                                topLeft: Radius.circular(13),
                                                bottomLeft:
                                                    Radius.circular(13)),
                                            boxShadow: [
                                              BoxShadow(
                                                  color: Color(0x4D0E96FF),
                                                  blurRadius: 2.0,
                                                  offset: Offset(0.0, 3.0),
                                                  //阴影y轴偏移量
                                                  spreadRadius: 0 //阴影扩散程度
                                                  )
                                            ],
                                          )))))
                        ],
                      ),
                      decoration: const BoxDecoration(
                          boxShadow: [
                            BoxShadow(
                                color: Color(0x4D0E96FF),
                                blurRadius: 5.0,
                                offset: Offset(0.0, 8.0), //阴影y轴偏移量
                                spreadRadius: 0 //阴影扩散程度
                                )
                          ],
                          gradient: LinearGradient(
                              stops: [.5, 1],
                              colors: [Color(0xFF4699FF), Color(0xFF00DEFF)]),
                          color: Colors.white,
                          borderRadius:
                              BorderRadius.all(Radius.elliptical(10, 10))))
                ],
              ),
            ),
            Container(
              child: adView ?? Container(),
              margin: EdgeInsets.only(left: 10, right: 10),
            ),
            //广告
            //功能区域
            Container(
              height: 340,
              margin: const EdgeInsets.all(10),
              padding: const EdgeInsets.all(10),
              decoration: const BoxDecoration(
                  borderRadius: BorderRadius.all(Radius.elliptical(10, 10)),
                  color: Color(0xFFF4FFFF)),
              child: GridView(
                  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                      crossAxisCount: 4, mainAxisSpacing: 10),
                  physics: const NeverScrollableScrollPhysics(),
                  children: list),
            ),
          ],
        )));
  }
  @override
  bool get wantKeepAlive => true;
}
class Functions {
  Functions(this.icon, this.name, this.key, this.needLogin);
  String icon;
  String name;
  String key;
  bool needLogin;
}
src/main/resources/code/flutter/lib/ui/mine/advice.dart
New file
@@ -0,0 +1,147 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../ui/widget/nav.dart';
import '../../utils/pageutils.dart';
import 'advice_submit.dart';
import 'package:launch_review/launch_review.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: '意见反馈',
      theme: ThemeData(primaryColor: Color(0xFFF5F5F5)),
      home: AdvicePage(title: ''),
    );
  }
}
class AdvicePage extends StatefulWidget {
  AdvicePage({Key? key, required this.title}) : super(key: key);
  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.
  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".
  final String title;
  @override
  _AdvicePageState createState() => _AdvicePageState();
}
class _AdvicePageState extends State<AdvicePage>
    with SingleTickerProviderStateMixin {
  @override
  void initState() {
    super.initState();
  }
  BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) {
    return BoxDecoration(
        borderRadius: BorderRadius.all(Radius.elliptical(10, 10)),
        color: bgColor,
        boxShadow: [
          BoxShadow(
              color: shadowColor,
              blurRadius: 2.0,
              offset: Offset(0.0, 5.0), //阴影y轴偏移量
              spreadRadius: 1 //阴影扩散程度
              )
        ]);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Color(0xFFFFFFFF),
        body: Container(
          child: Flex(
            direction: Axis.vertical,
            children: [
              TopNavBar(title: "意见反馈"),
              Image.asset("assets/imgs/advice/ic_advice_top.png"),
              getItemView(
                bgColor: Color(0xFFFFC945),
                shadowColor: Color(0x4DFCA235),
                title: "提意见",
                subTitle: "有建议,请留言",
                icon: "assets/imgs/advice/icon_advice_msg.png",
                onTap: () {
                  Navigator.of(context)
                      .push(CustomRouteSlide(AdviceSubmitPage(title: "")));
                },
              ),
              getItemView(
                bgColor: const Color(0xFF29D5FF),
                shadowColor: const Color(0x4D0E96FF),
                title: "给鼓励",
                subTitle: "您的鼓励是我们前进的动力",
                icon: "assets/imgs/advice/icon_advice_like.png",
                onTap: () {
                  LaunchReview.launch();
                },
              ),
            ],
          ),
        ));
  }
  Widget getItemView(
      {required Color bgColor,
      required Color shadowColor,
      required String title,
      required String subTitle,
      required String icon,
      required GestureTapCallback onTap}) {
    return InkWell(
      onTap: () {
        onTap();
      },
      child: Container(
        height: 92.5,
        padding: EdgeInsets.fromLTRB(20, 0, 24, 0),
        margin: EdgeInsets.fromLTRB(10, 12.5, 10, 4),
        decoration: getItemDecoration(bgColor, shadowColor),
        child: Flex(
          direction: Axis.horizontal,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Flex(
              direction: Axis.vertical,
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  title,
                  style: TextStyle(color: Colors.white, fontSize: 24),
                ),
                Text(
                  subTitle,
                  style: TextStyle(color: Colors.white, fontSize: 14),
                )
              ],
            ),
            Expanded(child: Container()),
            Image.asset(
              icon,
              height: 62,
            )
          ],
        ),
      ),
    );
  }
}
src/main/resources/code/flutter/lib/ui/mine/advice_submit.dart
New file
@@ -0,0 +1,199 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../api/http.dart';
import '../../ui/widget/nav.dart';
import '../../utils/string_util.dart';
import '../../utils/ui_utils.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: '提意见',
      theme: ThemeData(primaryColor: Color(0xFFF5F5F5)),
      home: AdviceSubmitPage(title: ''),
    );
  }
}
class AdviceSubmitPage extends StatefulWidget {
  AdviceSubmitPage({Key? key, required this.title}) : super(key: key);
  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.
  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".
  final String title;
  @override
  _AdviceSubmitPageState createState() => _AdviceSubmitPageState();
}
class _AdviceSubmitPageState extends State<AdviceSubmitPage>
    with SingleTickerProviderStateMixin {
  List<String> questions = ["账号问题", "定位问题", "其他问题"];
  final TextEditingController _contentController = TextEditingController();
  @override
  void initState() {
    super.initState();
  }
  BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) {
    return BoxDecoration(
        borderRadius: BorderRadius.all(Radius.elliptical(10, 10)),
        color: bgColor,
        boxShadow: [
          BoxShadow(
              color: shadowColor,
              blurRadius: 2.0,
              offset: Offset(0.0, 5.0), //阴影y轴偏移量
              spreadRadius: 1 //阴影扩散程度
              )
        ]);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        resizeToAvoidBottomInset: false,
        backgroundColor: Color(0xFFFFFFFF),
        body: Container(
          child: Flex(
            direction: Axis.vertical,
            children: [
              TopNavBar(title: "提意见"),
              Container(
                padding: const EdgeInsets.fromLTRB(17.5, 15, 17.5, 15),
                decoration: BoxDecoration(
                    color: const Color(0xFFFAFAFA),
                    border: Border.all(color: Color(0xFFDBDBDB))),
                child: Flex(
                  direction: Axis.vertical,
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Wrap(
                      children: getQuestionTypes(),
                    ),
                    Container(
                      child: TextField(
                        controller: _contentController,
                        maxLines: 9,
                        maxLength: 200,
                        decoration: const InputDecoration(
                            focusedBorder: InputBorder.none,
                            border: InputBorder.none,
                            counterStyle: TextStyle(color: Color(0xFF666666)),
                            hintText: "请描述您要反馈的问题或意见",
                            hintStyle: TextStyle(
                                fontSize: 15, color: Color(0xFF999999))),
                        style:
                            TextStyle(color: Color(0xFF666666), fontSize: 15),
                        onChanged: (value) {},
                      ),
                    )
                  ],
                ),
              ),
              //按钮
              Container(
                margin: EdgeInsets.fromLTRB(18, 50, 18, 0),
                child: InkWell(
                  onTap: () {
                    var content = _contentController.text;
                    if (StringUtil.isNullOrEmpty(content)) {
                      ToastUtil.toast("请填写问题");
                      return;
                    }
                    var type;
                    if (checkIndex > -1) {
                      type = questions[checkIndex];
                    }
                    FeedBackApiUtil.advice(context, type, content).then((value) {
                      if (value == null) {
                        return;
                      }
                      if (value["code"] == 0) {
                        Navigator.of(context).pop();
                      } else {
                        ToastUtil.toast(value["msg"]);
                      }
                    });
                  },
                  child: Container(
                    height: 42.5,
                    alignment: Alignment.center,
                    decoration: const BoxDecoration(
                        color: Color(0xFF0E96FF),
                        borderRadius: BorderRadius.all(Radius.circular(10))),
                    child: const Text(
                      "提交反馈",
                      style: TextStyle(color: Colors.white, fontSize: 18),
                    ),
                  ),
                ),
              )
            ],
          ),
        ));
  }
  int checkIndex = -1;
  List<Widget> getQuestionTypes() {
    List<Widget> list = [];
    for (int i = 0; i < questions.length; i++) {
      list.add(InkWell(
          onTap: () {
            if (checkIndex == i) {
              setState(() {
                checkIndex = -1;
              });
            } else {
              setState(() {
                checkIndex = i;
              });
            }
          },
          child: Container(
            alignment: Alignment.center,
            padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
            margin: EdgeInsets.fromLTRB(0, 0, 17.5, 0),
            height: 35,
            width: 80,
            decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(17.5),
                border: Border.all(
                    color: i == checkIndex
                        ? Color(0xFF0E96FF)
                        : Color(0xFFB4B4B4))),
            child: Text(
              questions[i],
              style: TextStyle(
                  color:
                      i == checkIndex ? Color(0xFF0E96FF) : Color(0xFF666666),
                  fontSize: 14),
            ),
          )));
    }
    return list;
  }
}
src/main/resources/code/flutter/lib/ui/mine/login.dart
New file
@@ -0,0 +1,495 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx;
import 'package:html/dom.dart' as dom;
import '../../api/http.dart';
import '../../model/user/user_info.dart';
import '../../ui/common/browser.dart';
import '../../ui/widget/button.dart';
import '../../utils/event_bus_util.dart';
import '../../utils/pageutils.dart';
import '../../utils/push_util.dart';
import '../../utils/string_util.dart';
import '../../utils/ui_constant.dart';
import '../../utils/ui_utils.dart';
import '../../utils/user_util.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.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: '登录',
      theme: ThemeData(primaryColor: Color(0xFFF5F5F5)),
      home: LoginPage(title: ''),
    );
  }
}
class LoginPage extends StatefulWidget {
  //阿里云一键登录
  static const messageChannel =
      BasicMessageChannel('AliyunPhoneNumberAuth', StandardMessageCodec());
  LoginPage({Key? key, required this.title}) : super(key: key);
  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.
  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".
  final String title;
  @override
  _LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage>
    with SingleTickerProviderStateMixin {
  bool oneKeyLogin = false;
  bool checked = false;
  TextEditingController? phoneController = TextEditingController();
  TextEditingController? codeController = TextEditingController();
  String phone = "";
  String code = "";
  Timer? timer;
  //重新发送验证码倒计时
  int? reSendSMSTimeLeft;
  @override
  void initState() {
    super.initState();
    reSendSMSTimeLeft = -1;
    //初始化微信登录监听
    fluwx.weChatResponseEventHandler.distinct((a, b) => a == b).listen((res) {
      if (res is fluwx.WeChatAuthResponse) {
        int errCode = res.errCode;
        if (errCode == 0) {
          String? code = res.code;
          //TODO 把微信登录返回的code传给后台,剩下的事就交给后台处理
        } else if (errCode == -4) {
          //showToast("用户拒绝授权");
        } else if (errCode == -2) {
          // showToast("用户取消授权");
        }
      }
    });
  }
  bool _aliyunLogin = false;
  void aliyunOneKeyLogin() async {
    if (_aliyunLogin) {
      return;
    }
    _aliyunLogin = true;
    Future.delayed(const Duration(milliseconds: 1000), () {
      _aliyunLogin = false;
    });
    showLoading(context);
    Map value =
        await LoginPage.messageChannel.send({"method": "checkEnv"}) as Map;
    dismissDialog(context);
    if (value["code"] == 0) {
      value =
          await LoginPage.messageChannel.send({"method": "startLogin"}) as Map;
      print("返回内容:${jsonEncode(value)}");
      if (value["code"] == 0) {
        Map<String, dynamic>? resultValue =
            await UserApiUtil.login(context, "", "", value["token"]);
        LoginPage.messageChannel.send({"method": "closeLogin"});
        if (resultValue == null) return;
        if (resultValue["code"] == 0) {
          UserInfo user = UserInfo.fromJson(resultValue["data"]);
          _loginSuccess(user);
        } else {
          Fluttertoast.showToast(msg: value["msg"]);
        }
      } else if (value["code"] == 700000) {
        //Fluttertoast.showToast(msg: "取消登录了");
      }
    } else {
      Fluttertoast.showToast(msg: value["msg"]);
      setState(() {
        oneKeyLogin = false;
      });
    }
  }
  void qqLogin() async {
    Map value = await UserUtil.loginQQ();
  }
  void _loginSuccess(UserInfo user) {
    UserUtil.setUserInfo(user).then((value) {
      print("登录成功");
      eventBus.fire(LoginEventBus(true));
      PushUtil.setAlias(user.id!.toString()).then((value) {
        Navigator.pop(context);
      });
    });
  }
  @override
  void dispose() {
    if (timer != null) {
      timer!.cancel();
    }
    super.dispose();
  }
  BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) {
    return BoxDecoration(
        borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)),
        color: bgColor,
        boxShadow: [
          BoxShadow(
              color: shadowColor,
              blurRadius: 2.0,
              offset: Offset(0.0, 5.0), //阴影y轴偏移量
              spreadRadius: 1 //阴影扩散程度
              )
        ]);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        resizeToAvoidBottomInset: false,
        backgroundColor: Colors.white,
        body: Stack(
          children: [
            Column(children: [
              //登录内容区域
              Expanded(
                  child: SingleChildScrollView(
                      child: Padding(
                          padding: EdgeInsets.fromLTRB(40, 100, 40, 14),
                          child: Column(
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: [
                                Image.asset(
                                  "assets/imgs/login/ic_login_logo.png",
                                  width: 131,
                                ),
                                Container(
                                  height: 70,
                                ),
                                Container(
                                    constraints: BoxConstraints(minHeight: 200),
                                    child: getLoginContent()),
                                Container(
                                  height: 30,
                                ),
                                Text(
                                  "其他方式登录",
                                  style: TextStyle(
                                      color: Color(0xFF666666), fontSize: 14),
                                ),
                                Container(
                                  height: 21,
                                ),
                                Row(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceAround,
                                  children: [
                                    // getThirdLoginItem("微信登录",
                                    //     "assets/images/login/ic_login_wx.png"),
                                    // getThirdLoginItem("QQ登录",
                                    //     "assets/images/login/ic_login_qq.png"),
                                    oneKeyLogin
                                        ? getThirdLoginItem("手机号登录",
                                            "assets/imgs/login/ic_login_phone.png")
                                        : getThirdLoginItem("一键登录",
                                            "assets/imgs/login/ic_login_onekey.png"),
                                  ],
                                )
                              ])))),
              //用户协议与隐私政策
              Row(children: [
                Container(
                  width: 25,
                ),
                RoundCheckBox(
                  value: checked,
                  onChanged: (value) {
                    setState(() {
                      checked = value;
                    });
                  },
                ),
                Expanded(
                    child: Container(
                        child: HtmlWidget(
                            "<p>登录即表明同意&nbsp;<a href='${Constant.PROTOCOL_URL}'>用户协议</a>&nbsp;和&nbsp;<a href='${Constant.PRIVACY_URL}'>隐私政策</a>&nbsp;</p>",
                            textStyle:
                                const TextStyle(color: Color(0xFF999999)),
                            onTapUrl: (url) {
                  String? title = "";
                  if (url == Constant.PROTOCOL_URL) {
                    title = "用户协议";
                  } else {
                    title = "隐私政策";
                  }
                  NavigatorUtil.navigateToNextPage(
                      context,
                      BrowserPage(
                        title: title,
                        url: url,
                      ),
                      (data) {});
                  return true;
                }))),
              ])
            ]),
            //关闭按钮
            Positioned(
                top: 30,
                left: 20,
                child: InkWell(
                    onTap: () {
                      Navigator.of(context).pop();
                    },
                    child: Icon(
                      Icons.close,
                      size: 30,
                    )))
          ],
        ));
  }
  Widget getLoginContent() {
    return oneKeyLogin
        ? Container(
            child: Column(children: [
            MyFillButton(
              "本机号码一键登录",
              10,
              height: 45,
              fontSize: 17,
              onClick: () {
                aliyunOneKeyLogin();
              },
            )
          ]))
        : Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Container(
                alignment: Alignment.centerLeft,
                padding: EdgeInsets.fromLTRB(20, 0, 5, 0),
                decoration: BoxDecoration(
                    color: const Color(0xFFF5F5F5),
                    borderRadius: BorderRadius.circular(10)),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Image.asset(
                      "assets/imgs/login/icon_phone.png",
                      width: 14,
                      height: 20,
                    ),
                    Container(width: 14),
                    Expanded(
                        child: TextField(
                      style: TextStyle(color: Color(0xFF333333), fontSize: 17),
                      onChanged: (value) {
                        setState(() {
                          phone = value;
                        });
                      },
                      textAlign: TextAlign.start,
                      keyboardType: TextInputType.phone,
                      controller: phoneController,
                      maxLength: 11,
                      decoration: InputDecoration(
                        counterText: "",
                        hintText: "请输入手机号",
                        hintStyle:
                            TextStyle(color: Color(0xFFCCCCCC), fontSize: 17),
                        contentPadding: EdgeInsets.only(bottom: 3),
                        border: InputBorder.none,
                        focusedBorder: InputBorder.none,
                      ),
                    )),
                  ],
                ),
              ),
              Container(height: 10),
              Container(
                alignment: Alignment.centerLeft,
                padding: EdgeInsets.fromLTRB(20, 0, 7, 0),
                decoration: BoxDecoration(
                    color: const Color(0xFFF5F5F5),
                    borderRadius: BorderRadius.circular(10)),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Image.asset(
                      "assets/imgs/login/icon_code.png",
                      width: 16,
                    ),
                    Container(width: 14),
                    Expanded(
                        child: TextField(
                      style: TextStyle(color: Color(0xFF333333), fontSize: 17),
                      onChanged: (value) {
                        setState(() {
                          phone = value;
                        });
                      },
                      textAlign: TextAlign.start,
                      keyboardType: TextInputType.phone,
                      controller: codeController,
                      maxLength: 8,
                      decoration: const InputDecoration(
                        counterText: "",
                        hintText: "请输入验证码",
                        hintStyle:
                            TextStyle(color: Color(0xFFCCCCCC), fontSize: 17),
                        contentPadding: EdgeInsets.only(bottom: 3),
                        border: InputBorder.none,
                        focusedBorder: InputBorder.none,
                      ),
                    )),
                    MyFillButton(
                      (reSendSMSTimeLeft! > 0
                              ? (reSendSMSTimeLeft.toString() + "S重新获取")
                              : reSendSMSTimeLeft == -1
                                  ? "获取验证码"
                                  : "重新获取")
                          .toString(),
                      10,
                      height: 34,
                      padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
                      enable: (reSendSMSTimeLeft! < 1 &&
                          StringUtil.isMobile(phoneController!.value.text)),
                      onClick: () {
                        if (!(reSendSMSTimeLeft! < 1 &&
                            StringUtil.isMobile(phoneController!.value.text))) {
                          return;
                        }
                        //发送验证码
                        UserApiUtil.sendSMS(
                                context, phoneController!.value.text)
                            .then((value) {
                          if (value != null && value["code"] == 0) {
                            setState(() {
                              reSendSMSTimeLeft = 60;
                              //倒计时
                              timer = Timer.periodic(const Duration(seconds: 1),
                                  (timer) {
                                if (reSendSMSTimeLeft! > 0) {
                                  setState(() {
                                    reSendSMSTimeLeft = reSendSMSTimeLeft! - 1;
                                  });
                                } else {
                                  timer.cancel();
                                }
                              });
                            });
                          } else {
                            ToastUtil.toast(value!["msg"]);
                          }
                        });
                      },
                    ),
                  ],
                ),
              ),
              Container(height: 10),
              const Text("未注册的手机号注册后系统会自动创建账户",
                  style: TextStyle(color: Color(0xFFA0A0A0), fontSize: 12)),
              Container(height: 20),
              MyFillButton(
                "登录",
                10,
                height: 45,
                color: const Color(0xFFFF2B4B),
                fontSize: 17,
                enable: StringUtil.isMobile(phoneController!.value.text) &&
                    codeController!.value.text.length >= 4,
                onClick: () {
                  if (!(StringUtil.isMobile(phoneController!.value.text) &&
                      codeController!.value.text.length >= 4)) {
                    return;
                  }
                  if (!checked) {
                    Fluttertoast.showToast(msg: "请同意用户协议与隐私政策");
                    return;
                  }
                  UserApiUtil.login(context, phoneController!.value.text,
                          codeController!.value.text, "")
                      .then((value) {
                    print("结果: $value");
                    if (value!["code"] == 0) {
                      UserInfo user = UserInfo.fromJson(value["data"]);
                      _loginSuccess(user);
                    } else {
                      Fluttertoast.showToast(msg: value["msg"]);
                    }
                  });
                },
              ),
            ],
          );
  }
  Widget getThirdLoginItem(String name, String iconAsset) {
    return InkWell(
      onTap: () {
        if (name == "一键登录" || name == "手机号登录") {
          setState(() {
            oneKeyLogin = !oneKeyLogin;
          });
        } else if (name == "QQ登录") {
          qqLogin();
        } else if (name == "微信登录") {
          UserUtil.loginWX();
        }
      },
      child: Container(
          constraints: BoxConstraints(minWidth: 80),
          child: Column(
            children: [
              Image.asset(
                iconAsset,
                height: 49,
              ),
              Container(
                height: 8,
              ),
              Text(
                name,
                style: const TextStyle(color: Color(0xFF9DAAB3), fontSize: 12),
              )
            ],
          )),
    );
  }
}
src/main/resources/code/flutter/lib/ui/mine/settings.dart
New file
@@ -0,0 +1,339 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../api/http.dart';
import '../../ui/common/browser.dart';
import '../../ui/widget/dialog.dart';
import '../../ui/widget/nav.dart';
import '../../utils/cache_util.dart';
import '../../utils/config_util.dart';
import '../../utils/event_bus_util.dart';
import '../../utils/pageutils.dart';
import '../../utils/push_util.dart';
import '../../utils/setting_util.dart';
import '../../utils/string_util.dart';
import '../../utils/ui_constant.dart';
import '../../utils/ui_utils.dart';
import '../../utils/user_util.dart';
import 'package:package_info/package_info.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: '设置',
      theme: ThemeData(primaryColor: const Color(0xFFF5F5F5)),
      home: SettingPage(title: ''),
    );
  }
}
class SettingPage extends StatefulWidget {
  SettingPage({Key? key, required this.title}) : super(key: key);
  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.
  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".
  final String title;
  @override
  _SettingPageState createState() => _SettingPageState();
}
class _SettingPageState extends State<SettingPage>
    with SingleTickerProviderStateMixin {
  bool msg = false;
  bool ad = false;
  bool login = false;
  String cacheSize = "0B";
  String version = "";
  @override
  void initState() {
    super.initState();
    UserUtil.isLogin().then((value) {
      setState(() {
        login = value;
      });
    });
    _getCacheSize();
    _getVersion();
    SettingUtil.isEnablePush().then((value) {
      setState(() {
        msg = value;
      });
    });
    SettingUtil.isEnableRecommendAd().then((value) {
      ad = value;
    });
  }
  ///获取缓存大小
  void _getCacheSize() async {
    int byteSize = await CacheUtil.total();
    String? desc;
    if (byteSize < 1000) {
      desc = byteSize.toString() + "KB";
    } else if (byteSize < 1000 * 1000) {
      desc = (byteSize / 1000).toStringAsFixed(0) + "KB";
    } else if (byteSize < 1000 * 1000 * 1000) {
      desc = (byteSize / (1000 * 1000)).toStringAsFixed(1) + "MB";
    } else {
      desc = (byteSize / (1000 * 1000 * 1000)).toStringAsFixed(1) + "GB";
    }
    setState(() {
      cacheSize = desc!;
    });
  }
  void _getVersion() async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    setState(() {
      version = packageInfo.version;
    });
  }
  Future logout() async {
    var uid = await UserUtil.getUid();
    Map<String, dynamic>? map = await UserApiUtil.logout(context, uid);
    if (map!["code"] == 0) {
      UserUtil.logout();
      setState(() {
        login = false;
      });
      ToastUtil.toast("退出成功");
      Navigator.of(context).pop();
    } else {
      ToastUtil.toast(map["msg"]);
    }
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: const Color(0xFFF5F5F5),
        body: Flex(
          direction: Axis.vertical,
          children: [
            TopNavBar(title: "设置"),
            getBigItemView(
                title: "推送免打扰",
                content: "关闭后,21:00-09:00不接受任何推送",
                marginTop: 14,
                marginBottom: 1,
                checked: msg,
                changed: (bool value) {
                  SettingUtil.setPush(value).then((value1) {
                    setState(() {
                      msg = value;
                    });
                  });
                }),
            getBigItemView(
                title: "个性化广告推荐",
                content: "关闭后,广告数量将不变,但内容相关度会降低",
                marginTop: 0,
                marginBottom: 16,
                checked: ad,
                changed: (bool value) {
                  SettingUtil.setRecommendAd(value).then((value1) {
                    setState(() {
                      ad = value;
                    });
                  });
                }),
            getCommonItemView(
                title: "清理缓存",
                content: cacheSize,
                onClick: () {
                  DialogUtil.showDialog(
                      context,
                      NotifyDialog("温馨提示", "是否清楚缓存?", () {}, () {
                        CacheUtil.clear().then((value) {
                          ToastUtil.toast("缓存清除成功");
                          _getCacheSize();
                        });
                      }));
                }),
            getCommonItemView(
                title: "检查更新",
                content: "版本号:$version",
                onClick: () {
                  ToastUtil.toast("已经是最新版本");
                }),
            getCommonItemView(
                title: "账户注销",
                content: "",
                onClick: () {
                  ConfigUtil.getConfig(ConfigKey.unRegister).then((value) {
                    if (!StringUtil.isNullOrEmpty(value)) {
                      NavigatorUtil.navigateToNextPage(context,
                          BrowserPage(title: "账户注销", url: value!), (data) {});
                    }
                  });
                }),
            getCommonItemView(
                title: "隐私投诉",
                content: "",
                onClick: () {
                  ConfigUtil.getConfig(ConfigKey.privacyComplain).then((value) {
                    if (!StringUtil.isNullOrEmpty(value)) {
                      NavigatorUtil.navigateToNextPage(context,
                          BrowserPage(title: "隐私投诉", url: value!), (data) {});
                    }
                  });
                }),
            // getCommonItemView(
            //     title: "第三方SDK列表",
            //     content: "",
            //     onClick: () {
            //
            //       ConfigUtil.getConfig(ConfigKey.sdkList).then((value) {
            //         if (!StringUtil.isNullOrEmpty(value)) {
            //           NavigatorUtil.navigateToNextPage(
            //               context, BrowserPage(title: "第三方SDK列表", url: value!), (data) {});
            //         }
            //       });
            //     }),
            Expanded(
              child: Container(),
            ),
            login
                ? Container(
                    child: Stack(
                    children: [
                      InkWell(
                          onTap: () {
                            print("退出登录");
                            logout();
                          },
                          child: Container(
                              alignment: Alignment.center,
                              height: 48,
                              color: Colors.white,
                              child: const Text(
                                "退出登录",
                                style: TextStyle(
                                    color: ColorConstant.theme, fontSize: 16),
                              )))
                    ],
                  ))
                : Container(),
          ],
        ));
  }
  Widget getCommonItemView(
      {required String title,
      String content = "",
      required GestureTapCallback onClick}) {
    return Container(
      height: 53,
      margin: const EdgeInsets.fromLTRB(0, 0, 0, 1),
      color: Colors.white,
      child: InkWell(
        onTap: () {
          onClick();
        },
        child: Container(
            padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
            child: Flex(
              crossAxisAlignment: CrossAxisAlignment.center,
              direction: Axis.horizontal,
              children: [
                Text(
                  title,
                  style:
                      const TextStyle(fontSize: 16, color: Color(0xFF333333)),
                ),
                Expanded(
                    child: Flex(
                  direction: Axis.horizontal,
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                    Container(
                      child: Text(content,
                          style: const TextStyle(
                              fontSize: 14, color: Color(0xFF959595))),
                      margin: const EdgeInsets.fromLTRB(0, 0, 13.5, 0),
                    ),
                    Image.asset(
                      "assets/imgs/common/icon_array_right.png",
                      height: 13.5,
                    )
                  ],
                ))
              ],
            )),
      ),
    );
  }
  Widget getBigItemView(
      {required String title,
      String content = "",
      bool checked = false,
      required ValueChanged<bool> changed,
      double marginTop = 0,
      double marginBottom = 0}) {
    return Container(
      height: 68,
      margin: EdgeInsets.fromLTRB(0, marginTop, 0, marginBottom),
      color: Colors.white,
      child: Container(
          padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
          child: Stack(children: [
            Flex(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.center,
              direction: Axis.vertical,
              children: [
                Text(
                  title,
                  style: TextStyle(fontSize: 16, color: Color(0xFF333333)),
                ),
                Container(
                  child: Text(content,
                      style: const TextStyle(
                          fontSize: 9, color: Color(0xFF959595))),
                  margin: const EdgeInsets.fromLTRB(0, 5, 0, 0),
                )
              ],
            ),
            Container(),
            Positioned(
                right: 0,
                top: 0,
                bottom: 0,
                child: InkWell(
                    onTap: () {
                      changed(!checked);
                    },
                    child: Image.asset(
                      checked
                          ? "assets/imgs/common/icon_check_true.png"
                          : "assets/imgs/common/icon_check_false.png",
                      height: 30,
                      width: 60,
                    )))
          ])),
    );
  }
}
src/main/resources/code/flutter/lib/ui/widget/base_ui.dart
New file
@@ -0,0 +1,25 @@
import 'package:flutter/cupertino.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
WaterDropHeader refreshHeader = const WaterDropHeader(complete: Text("刷新成功"));
CustomFooter loadFotter = CustomFooter(
  builder: (BuildContext context, LoadStatus? mode) {
    Widget body;
    if (mode == LoadStatus.idle) {
      body = Text("上拉加载");
    } else if (mode == LoadStatus.loading) {
      body = CupertinoActivityIndicator();
    } else if (mode == LoadStatus.failed) {
      body = Text("加载失败!点击重试!");
    } else if (mode == LoadStatus.canLoading) {
      body = Text("松手,加载更多!");
    } else {
      body = Text("没有更多数据了!");
    }
    return Container(
      height: 55.0,
      child: Center(child: body),
    );
  },
);
src/main/resources/code/flutter/lib/ui/widget/button.dart
New file
@@ -0,0 +1,134 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import '../../utils/ui_constant.dart';
class MyOutlineButton extends StatelessWidget {
  final String text;
  final double radius;
  final double height;
  final double? width;
  final Color color;
  final double fontSize;
  final GestureTapCallback? onClick;
  final EdgeInsets? padding;
  MyOutlineButton(this.text, this.radius,
      {GestureTapCallback? this.onClick,
      Color this.color = ColorConstant.theme,
      double this.height = 26,
      double this.fontSize = 12,
      double? this.width = null,
      EdgeInsets? this.padding = null});
  @override
  Widget build(BuildContext context) {
    Container child = Container(
      alignment: Alignment.center,
      height: height,
      width: width,
      padding: padding,
      decoration: BoxDecoration(
        color: Colors.transparent,
        border: Border.all(color: color, width: 1),
        borderRadius: BorderRadius.circular(radius),
      ),
      child: Text(
        text,
        style: TextStyle(color: color, fontSize: fontSize),
      ),
    );
    return InkWell(
        onTap: () {
          onClick!();
        },
        child: child);
  }
}
class MyFillButton extends StatelessWidget {
  final String text;
  final Color textColor;
  final double radius;
  final double height;
  final double? width;
  final Color color;
  final double fontSize;
  final GestureTapCallback? onClick;
  final EdgeInsets? padding;
  final bool? enable;
  MyFillButton(this.text, this.radius,
      {GestureTapCallback? this.onClick,
      Color this.color = ColorConstant.theme,
      Color this.textColor = Colors.white,
      double this.height = 26,
      double this.fontSize = 12,
      double? this.width = null,
      EdgeInsets? this.padding = null,
      bool? this.enable = true});
  @override
  Widget build(BuildContext context) {
    Container child = Container(
      alignment: Alignment.center,
      height: height,
      width: width,
      padding: padding,
      decoration: BoxDecoration(
        color: enable! ? color : const Color(0xFFCBCBCB),
        borderRadius: BorderRadius.circular(radius),
      ),
      child: Text(
        text,
        style: TextStyle(color: textColor, fontSize: fontSize),
      ),
    );
    return InkWell(
        onTap: () {
          onClick!();
        },
        child: child);
  }
}
class RoundCheckBox extends StatefulWidget {
  var value = false;
  Function(bool) onChanged;
  RoundCheckBox({Key? key, required this.value, required this.onChanged})
      : super(key: key);
  @override
  _RoundCheckBoxState createState() => _RoundCheckBoxState();
}
class _RoundCheckBoxState extends State<RoundCheckBox> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
          onTap: () {
            widget.value = !widget.value;
            widget.onChanged(widget.value);
          },
          child: Padding(
            padding: const EdgeInsets.all(10.0),
            child: widget.value
                ? const Icon(
                    Icons.check_circle,
                    size: 19,
                    color: Colors.green,
                  )
                : const Icon(
                    Icons.panorama_fish_eye,
                    size: 19,
                    color: Colors.black12,
                  ),
          )),
    );
  }
}
src/main/resources/code/flutter/lib/ui/widget/capture.dart
New file
@@ -0,0 +1,47 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
///对widget截图
class CaptureWidget extends StatelessWidget {
//截图组件
  GlobalKey rootWidgetKey = GlobalKey();
  final Widget widget;
  final CaptureController captureController;
  CaptureWidget({required this.widget, required this.captureController}) {
    captureController.setGlobalKey(rootWidgetKey);
  }
  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(key: rootWidgetKey, child: widget);
  }
}
class CaptureController {
  GlobalKey? _globalKey;
  setGlobalKey(GlobalKey globalKey) {
    _globalKey = globalKey;
  }
  Future<String> capturePng() async {
    try {
      RenderRepaintBoundary? boundary = _globalKey!.currentContext!
          .findRenderObject() as RenderRepaintBoundary;
      var image = await boundary.toImage(pixelRatio: 3.0);
      ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
      Uint8List pngBytes = byteData!.buffer.asUint8List();
      String str = base64.encode(pngBytes);
      return str;
    } catch (e) {}
    return "";
  }
}
src/main/resources/code/flutter/lib/ui/widget/dialog.dart
New file
@@ -0,0 +1,559 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:html/dom.dart' as dom;
import '../../ui/common/browser.dart';
import '../../utils/pageutils.dart';
import '../../utils/ui_constant.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
//通用弹框
class NotifyDialog extends Dialog {
  BuildContext? context;
  final String title;
  final String content;
  final GestureTapCallback onCancel;
  final GestureTapCallback onSure;
  final bool richText;
  final double fontSize;
  final double height;
  final Color contentColor;
  bool touchOutCancel = false;
  final String cancelName;
  final String sureName;
  NotifyDialog(this.title, this.content, this.onCancel, this.onSure,
      {this.fontSize = 16.0,
      this.richText = false,
      this.height = 240,
      this.contentColor = const Color(0xFF7E7E7E),
      this.cancelName = "取消",
      this.sureName = "确定"});
  Widget getContent(BuildContext context) {
    if (richText) {
      return SingleChildScrollView(
          child: HtmlWidget(content, onTapUrl: (String url) {
        NavigatorUtil.navigateToNextPage(
            context,
            BrowserPage(
              title: "",
              url: url,
            ),
            (data) {});
        return true;
      }));
    } else {
      return Text(
        content,
        style: TextStyle(color: contentColor, fontSize: fontSize),
      );
    }
  }
  Offset? offset;
  @override
  Widget build(BuildContext context) {
    this.context = context;
    double width = MediaQuery.of(context).size.width;
    double dialogWidth = width * 4 / 5;
    print("屏幕宽:$width");
    //关闭弹框
    // Navigator.pop(context);
    return WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: Material(
            type: MaterialType.transparency,
            child: Align(
                alignment: Alignment.center,
                child: Container(
                  decoration: const BoxDecoration(
                      borderRadius: BorderRadius.all(Radius.circular(15)),
                      color: Colors.white),
                  alignment: Alignment.topCenter,
                  height: height,
                  width: dialogWidth,
                  child: Flex(
                    mainAxisAlignment: MainAxisAlignment.start,
                    direction: Axis.vertical,
                    children: [
                      //-------标题区域--------
                      Container(
                          alignment: Alignment.center,
                          height: 60,
                          child: Text(
                            title,
                            style: TextStyle(fontSize: 18, color: Colors.white),
                          ),
                          decoration: const BoxDecoration(
                            color: Color(0xFF1CC7FF),
                            borderRadius: BorderRadius.only(
                                topLeft: Radius.circular(15),
                                topRight: Radius.circular(15)),
                          )),
                      //-------内容区域--------
                      Expanded(
                          child: Container(
                        alignment: Alignment.center,
                        padding: const EdgeInsets.fromLTRB(15, 5, 15, 5),
                        child: getContent(context),
                      )),
                      //------按钮区域--------
                      Flex(
                        direction: Axis.horizontal,
                        children: [
                          Expanded(
                              child: InkWell(
                            onTap: () {
                              Navigator.pop(context);
                              onCancel();
                            },
                            child: Container(
                              margin: EdgeInsets.fromLTRB(15, 0, 6, 15),
                              alignment: Alignment.center,
                              height: 44,
                              decoration: BoxDecoration(
                                  border: Border.all(color: Color(0xFF0E96FF)),
                                  borderRadius: BorderRadius.circular(10)),
                              child: Text(
                                cancelName,
                                style: const TextStyle(
                                    color: Color(0xFF0E96FF), fontSize: 18),
                              ),
                            ),
                          )),
                          Expanded(
                              child: InkWell(
                            onTap: () {
                              Navigator.pop(context);
                              onSure();
                            },
                            child: Container(
                              margin: const EdgeInsets.fromLTRB(6, 0, 15, 15),
                              alignment: Alignment.center,
                              height: 44,
                              decoration: BoxDecoration(
                                  color: Color(0xFF0E96FF),
                                  borderRadius: BorderRadius.circular(10)),
                              child: Text(
                                sureName,
                                style: const TextStyle(
                                    color: Colors.white, fontSize: 18),
                              ),
                            ),
                          ))
                        ],
                      )
                    ],
                  ),
                ))));
  }
}
///权限弹框
class PermissionNotifyDialog extends Dialog {
  final GestureTapCallback onOpen;
  PermissionNotifyDialog(this.onOpen);
  @override
  Widget build(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    double dialogWidth = width * 4 / 5;
    print("屏幕宽:$width");
    //关闭弹框
    // Navigator.pop(context);
    return WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: Material(
            type: MaterialType.transparency,
            child: Align(
                alignment: Alignment.center,
                child: Container(
                    width: dialogWidth,
                    child: Flex(
                      mainAxisAlignment: MainAxisAlignment.center,
                      direction: Axis.vertical,
                      children: [
                        Image.asset(
                            "assets/imgs/common/ic_permission_notify_top.png"),
                        Container(
                          padding: EdgeInsets.all(16),
                          decoration: BoxDecoration(
                              borderRadius: BorderRadius.only(
                                  bottomLeft: Radius.circular(15),
                                  bottomRight: Radius.circular(15)),
                              color: Colors.white),
                          child: Flex(
                            direction: Axis.vertical,
                            children: [
                              getPermissionItem(
                                  title: "手机",
                                  content: "校验手机识别码,防止账号被盗",
                                  icon: Image.asset(
                                    "assets/imgs/common/icon_permission_notify_phone.png",
                                    width: 21,
                                  )),
                              Container(
                                height: 30,
                              ),
                              getPermissionItem(
                                  title: "存储",
                                  content: "缓存图片和视频,降低流量消耗",
                                  icon: Image.asset(
                                    "assets/imgs/common/icon_permission_notify_save.png",
                                    width: 26,
                                  )),
                              Container(
                                height: 30,
                              ),
                              getPermissionItem(
                                  title: "位置",
                                  content: "定位用户",
                                  icon: Image.asset(
                                    "assets/imgs/common/icon_permission_notify_location.png",
                                    width: 26,
                                  )),
                              Container(
                                height: 36,
                              ),
                              InkWell(
                                onTap: () {
                                  onOpen();
                                },
                                child: Container(
                                  height: 44,
                                  alignment: Alignment.center,
                                  decoration: BoxDecoration(
                                      borderRadius: BorderRadius.circular(10),
                                      color: const Color(0xFF0E96FF)),
                                  child: const Text(
                                    "立即开启",
                                    style: TextStyle(
                                        fontSize: 18, color: Colors.white),
                                  ),
                                ),
                              )
                            ],
                          ),
                        ),
                      ],
                    )))));
  }
  //权限项
  Widget getPermissionItem(
      {required Image icon, required String title, required String content}) {
    return Flex(
      direction: Axis.horizontal,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Container(
          width: 34,
        ),
        icon,
        Container(
          width: 4,
        ),
        Expanded(
            child: Flex(
          crossAxisAlignment: CrossAxisAlignment.start,
          direction: Axis.vertical,
          children: [
            Text(title,
                style: TextStyle(fontSize: 17, color: Color(0xFF6B6B6B))),
            Text(content,
                style: TextStyle(fontSize: 12, color: Color(0xFFA0A0A0)),
                softWrap: false,
                overflow: TextOverflow.ellipsis)
          ],
        ))
      ],
    );
  }
}
///邀请定位
class RequireLocationDialog extends Dialog {
  BuildContext? context;
  final String phone;
  final GestureTapCallback onCancel;
  final GestureTapCallback onSure;
  RequireLocationDialog(this.phone, this.onCancel, this.onSure);
  @override
  Widget build(BuildContext context) {
    this.context = context;
    double width = MediaQuery.of(context).size.width;
    double dialogWidth = width * 4 / 5;
    print("屏幕宽:$width");
    //关闭弹框
    // Navigator.pop(context);
    return WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: Material(
            type: MaterialType.transparency,
            child: Align(
                alignment: Alignment.center,
                child: Container(
                  decoration: const BoxDecoration(
                      borderRadius: BorderRadius.all(Radius.circular(15)),
                      color: Colors.white),
                  alignment: Alignment.topCenter,
                  height: 380,
                  width: dialogWidth,
                  child: Flex(
                    mainAxisAlignment: MainAxisAlignment.start,
                    direction: Axis.vertical,
                    children: [
                      //-------标题区域--------
                      Image.asset(
                          "assets/imgs/common/ic_require_location_top.png"),
                      //-------内容区域--------
                      Expanded(
                          child: Container(
                              alignment: Alignment.center,
                              padding: EdgeInsets.fromLTRB(15, 5, 15, 5),
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.center,
                                children: [
                                  Container(
                                    height: 15,
                                  ),
                                  const Text(
                                    "位置共享授权",
                                    style: TextStyle(
                                        color: Color(0xFF0E96FF), fontSize: 17),
                                  ),
                                  Container(
                                    height: 49,
                                  ),
                                  Row(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: [
                                      Image.asset(
                                        "assets/imgs/common/icon_require_location_phone.png",
                                        height: 15,
                                      ),
                                      Container(
                                        width: 10,
                                      ),
                                      Text(
                                        phone,
                                        style: TextStyle(
                                            color: Color(0xFF0E96FF),
                                            fontSize: 18),
                                      ),
                                    ],
                                  ),
                                  Container(
                                    height: 10,
                                  ),
                                  const Text(
                                    "该手机号用户请求与你进行位置共享。",
                                    style: TextStyle(
                                        color: Color(0xFF666666), fontSize: 15),
                                  ),
                                  Container(
                                    height: 10,
                                  ),
                                  const Text(
                                    "温馨提醒:你同意后可在定位人列表中删除",
                                    style: TextStyle(
                                        color: Color(0xFFA0A0A0), fontSize: 12),
                                  ),
                                ],
                              ))),
                      //------按钮区域--------
                      Flex(
                        direction: Axis.horizontal,
                        children: [
                          Expanded(
                              child: InkWell(
                            onTap: () {
                              onCancel();
                            },
                            child: Container(
                              margin: EdgeInsets.fromLTRB(15, 0, 6, 15),
                              alignment: Alignment.center,
                              height: 44,
                              decoration: BoxDecoration(
                                  border: Border.all(color: Color(0xFF0E96FF)),
                                  borderRadius: BorderRadius.circular(10)),
                              child: Text(
                                "不同意",
                                style: TextStyle(
                                    color: Color(0xFF0E96FF), fontSize: 18),
                              ),
                            ),
                          )),
                          Expanded(
                              child: InkWell(
                            onTap: () {
                              onSure();
                            },
                            child: Container(
                              margin: EdgeInsets.fromLTRB(6, 0, 15, 15),
                              alignment: Alignment.center,
                              height: 44,
                              decoration: BoxDecoration(
                                  color: Color(0xFF0E96FF),
                                  borderRadius: BorderRadius.circular(10)),
                              child: Text(
                                "同意",
                                style: TextStyle(
                                    color: Colors.white, fontSize: 18),
                              ),
                            ),
                          ))
                        ],
                      )
                    ],
                  ),
                ))));
  }
}
///ListView弹框
class ListViewDialog extends Dialog {
  BuildContext? context;
  final ListView listView;
  final GestureTapCallback onClose;
  final double maxHeight;
  final double? dwidth;
  ListViewDialog(this.listView, this.onClose,
      {this.maxHeight = 420, this.dwidth});
  @override
  Widget build(BuildContext context) {
    this.context = context;
    double swidth = MediaQuery.of(context).size.width;
    double dialogWidth = swidth - 20;
    print("屏幕宽:$swidth");
    if (dwidth != null) {
      dialogWidth = dwidth!;
    }
    //关闭弹框
    // Navigator.pop(context);
    return WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: Material(
            type: MaterialType.transparency,
            child: Align(
                alignment: Alignment.center,
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      ClipRRect(
                          borderRadius: BorderRadius.circular(10),
                          child: Container(
                            constraints: BoxConstraints(maxHeight: maxHeight),
                            color: Colors.white,
                            alignment: Alignment.topCenter,
                            width: dialogWidth,
                            child: listView,
                          )),
                      Container(
                        height: 20,
                      ),
                      InkWell(
                        child: Image.asset(
                          "assets/imgs/common/icon_dialog_close.png",
                          height: 32,
                          width: 32,
                        ),
                        onTap: () {
                          onClose();
                        },
                      ),
                    ]))));
  }
}
///ListView弹框
class LoadingDialog extends Dialog {
  BuildContext? context;
  final String? text;
  LoadingDialog(this.text);
  @override
  Widget build(BuildContext context) {
    this.context = context;
    //关闭弹框
    // Navigator.pop(context);
    return WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: const Material(
            type: MaterialType.transparency,
            child: Align(
                alignment: Alignment.center,
                child: SpinKitCircle(
                  color: ColorConstant.theme,
                  size: 80.0,
                ))));
  }
}
class CustomDialog extends Dialog {
  BuildContext? context;
  final Widget contentWidget;
  CustomDialog(this.contentWidget);
  @override
  Widget build(BuildContext context) {
    this.context = context;
    //关闭弹框
    // Navigator.pop(context);
    return WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: Material(
            type: MaterialType.transparency,
            child: Align(
                alignment: Alignment.center,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    contentWidget,
                    Container(
                      height: 20,
                    ),
                    InkWell(
                        onTap: () {
                          Navigator.of(context).pop();
                        },
                        child: Image.asset(
                          "assets/imgs/common/icon_dialog_close.png",
                          height: 32,
                          width: 32,
                        ))
                  ],
                ))));
  }
}
src/main/resources/code/flutter/lib/ui/widget/nav.dart
New file
@@ -0,0 +1,104 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class TopNavBar extends StatelessWidget {
  final String title;
  GestureTapCallback? back;
  String? rightText;
  Widget? rightIcon;
  GestureTapCallback? rightClick;
  final Color textColor;
  final Color backGround;
  final Image backIcon;
  TopNavBar(
      {required this.title,
      GestureTapCallback? this.back,
      String? this.rightText,
      Widget? this.rightIcon,
      GestureTapCallback? this.rightClick,
      Color this.textColor = const Color(0xFF333333),
      Color this.backGround = Colors.white,
      Image this.backIcon = const Image(
          image: AssetImage(
            "assets/imgs/common/icon_back.png",
          ),
          height: 19)});
  @override
  Widget build(BuildContext context) {
    return Flex(direction: Axis.vertical, children: [
      Container(
        height: MediaQuery.of(context).viewPadding.top,
        color: backGround,
      ),
      Container(
        color: backGround,
        height: 48,
        child: Stack(
          alignment: Alignment.centerLeft,
          children: [
            Positioned(
                child: Container(
                    alignment: Alignment.center,
                    child: Flex(
                      direction: Axis.horizontal,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Container(
                          width: 50,
                        ),
                        Expanded(
                            child: Center(
                                child: Text(
                          title,
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                          style: TextStyle(fontSize: 18, color: textColor),
                        ))),
                        Container(
                          width: 50,
                        )
                      ],
                    ))),
            ((rightText != null && rightText!.isNotEmpty) || rightIcon != null)
                ? Positioned(
                    right: 0,
                    top: 0,
                    bottom: 0,
                    child: InkWell(
                        onTap: () {
                          rightClick!();
                        },
                        child: Container(
                          alignment: Alignment.center,
                          padding: const EdgeInsets.only(right: 10),
                          child: rightIcon ?? Text(
                                  rightText!,
                                  style:
                                      TextStyle(fontSize: 15, color: textColor),
                                ),
                        )))
                : Container(),
            InkWell(
                onTap: () {
                  if (back != null) {
                    back!();
                  } else {
                    Navigator.pop(context);
                  }
                },
                child: Container(
                  alignment: Alignment.center,
                  width: 42,
                  height: 48,
                  child: backIcon,
                ))
          ],
        ),
      )
    ]);
  }
}
src/main/resources/code/flutter/lib/ui/widget/sos_ui.dart
New file
@@ -0,0 +1,105 @@
import 'dart:math';
import 'dart:ui' as ui;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
///SOS雷达扫描View
class RadarView extends StatefulWidget {
  @override
  _RadarViewState createState() => _RadarViewState();
}
class _RadarViewState extends State<RadarView>
    with SingleTickerProviderStateMixin {
  AnimationController? _controller;
  Animation<double>? _animation;
  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: Duration(seconds: 2));
    _animation = Tween(begin: .0, end: pi * 2).animate(_controller!);
    _controller!.repeat();
    super.initState();
  }
  @override
  void dispose() {
    _controller!.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation!,
      builder: (context, child) {
        return CustomPaint(
          painter: RadarPainter(_animation!.value),
        );
      },
    );
  }
}
///SOS雷达扫描动画
class RadarPainter extends CustomPainter {
  final double angle;
  final Paint _bgPaint = Paint()
    ..color = Colors.white
    ..strokeWidth = 1
    ..style = PaintingStyle.stroke;
  final Paint _paint = Paint()..style = PaintingStyle.fill;
  int circleCount = 0;
  RadarPainter(this.angle);
  @override
  void paint(Canvas canvas, Size size) {
    var radius = min(size.width / 2, size.height / 2);
    // canvas.drawLine(Offset(size.width / 2, size.height / 2 - radius),
    //     Offset(size.width / 2, size.height / 2 + radius), _bgPaint);
    // canvas.drawLine(Offset(size.width / 2 - radius, size.height / 2),
    //     Offset(size.width / 2 + radius, size.height / 2), _bgPaint);
    for (var i = 1; i <= circleCount; ++i) {
      canvas.drawCircle(Offset(size.width / 2, size.height / 2),
          radius * i / circleCount, _bgPaint);
    }
    _paint.shader = ui.Gradient.sweep(
        Offset(size.width / 2, size.height / 2),
        [Colors.white.withOpacity(.01), Colors.yellow.withOpacity(.6)],
        [.0, 1.0],
        TileMode.clamp,
        .0,
        pi / 4);
    canvas.save();
    double r = sqrt(pow(size.width, 2) + pow(size.height, 2));
    double startAngle = atan(size.height / size.width);
    Point p0 = Point(r * cos(startAngle), r * sin(startAngle));
    Point px = Point(r * cos(angle + startAngle), r * sin(angle + startAngle));
    canvas.translate((p0.x - px.x) / 2, (p0.y - px.y) / 2);
    canvas.rotate(angle);
    canvas.drawArc(
        Rect.fromCircle(
            center: Offset(size.width / 2, size.height / 2), radius: radius),
        0,
        pi / 4,
        true,
        _paint);
    canvas.restore();
  }
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
src/main/resources/code/flutter/lib/utils/ad_util.dart
New file
@@ -0,0 +1,610 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_unionad/flutter_unionad.dart';
import 'package:flutter_tencentad/flutter_tencentad.dart';
import '../model/common/adinfo_model.dart';
import 'config_util.dart';
import 'string_util.dart';
import 'ui_constant.dart';
//紧急联系人输入框确定事件
typedef OnAdCallback = void Function(bool success, String msg);
typedef OnRewardAdCallback = void Function(RewardAdStatus status, String msg);
enum RewardAdStatus { fail, click, ready, verify, close }
class AdUtil {
  static AdinfoModel? splashAdInfo;
  static Future init() async {
    await CSJAdUtil.init();
    await GDTAdUtil.init();
    splashAdInfo = await getAdInfo(AdPosition.splash);
  }
  static Widget loadSplash(AdinfoModel? adInfo, double width, double height,
      OnAdCallback adCallback) {
    if (adInfo == null) {
      adCallback(false, "广告信息为空");
      return Container();
    }
    if (StringUtil.isNullOrEmpty(adInfo.type)) {
      adCallback(false, "广告类型为空");
      return Container();
    }
    if (adInfo.type == "csj") {
      return CSJAdUtil.loadSplash(adInfo.pid!, width, height, adCallback);
    } else {
      return GDTAdUtil.loadSplash(adInfo.pid!, width, height, adCallback);
    }
  }
  static Widget? loadBanner(
      AdinfoModel? adInfo, double width, double height, OnAdCallback callback) {
    if (adInfo == null) {
      callback(false, "广告信息为空");
      return null;
    }
    if (StringUtil.isNullOrEmpty(adInfo.type)) {
      callback(false, "广告类型为空");
      return null;
    }
    if (adInfo.type == "csj") {
      return CSJAdUtil.loadBanner(adInfo.pid!, width, height, callback);
    } else {
      return GDTAdUtil.loadBanner(adInfo.pid!, width, height, callback);
    }
  }
  static Widget? loadExpress(
      AdinfoModel? adInfo, double width, double height, OnAdCallback callback) {
    if (adInfo == null) {
      callback(false, "广告信息为空");
      return null;
    }
    if (StringUtil.isNullOrEmpty(adInfo.type)) {
      callback(false, "广告类型为空");
      return null;
    }
    if (adInfo.type == "csj") {
      return CSJAdUtil.loadExpress(adInfo.pid!, width, height, callback);
    } else {
      return GDTAdUtil.loadExpress(adInfo.pid!, width, height, callback);
    }
  }
  static loadReward(AdinfoModel? adInfo, OnRewardAdCallback callback) async {
    if (adInfo == null) {
      callback(RewardAdStatus.fail, "广告信息为空");
      return null;
    }
    if (StringUtil.isNullOrEmpty(adInfo.type)) {
      callback(RewardAdStatus.fail, "广告类型为空");
      return null;
    }
    if (adInfo.type == "csj") {
      return CSJAdUtil.loadReward(adInfo.pid!, callback);
    } else {
      return GDTAdUtil.loadReward(adInfo.pid!, callback);
    }
  }
  static loadInterstitial(AdinfoModel? adInfo, OnAdCallback callback) async {
    if (adInfo == null) {
      return null;
    }
    if (StringUtil.isNullOrEmpty(adInfo.type)) {
      return null;
    }
    if (adInfo.type == "csj") {
      CSJAdUtil.loadInterstitial(adInfo.pid!, callback);
    } else {
      GDTAdUtil.loadInterstitial(adInfo.pid!, callback);
    }
  }
  static Future<AdinfoModel?> getAdInfo(String position) async {
    var result = await ConfigUtil.getConfig(position);
    if (result == null) {
      return null;
    }
    AdinfoModel model = AdinfoModel.fromJson(jsonDecode(result));
    if (StringUtil.isNullOrEmpty(model.type)) {
      return null;
    }
    return model;
  }
}
class CSJAdUtil {
  static Future init() async {
    var csjAppId = "5240078";
    //初始化穿山甲
    if (!StringUtil.isNullOrEmpty(csjAppId)) {
      // if (Platform.isAndroid) {
      //   await FlutterUnionad.andridPrivacy(
      //     isCanUseLocation: false,
      //     //是否允许SDK主动使用地理位置信息 true可以获取,false禁止获取。默认为true
      //     lat: 1.0,
      //     //当isCanUseLocation=false时,可传入地理位置信息,穿山甲sdk使用您传入的地理位置信息lat
      //     lon: 1.0,
      //     //当isCanUseLocation=false时,可传入地理位置信息,穿山甲sdk使用您传入的地理位置信息lon
      //     isCanUsePhoneState: false,
      //     //是否允许SDK主动使用手机硬件参数,如:imei
      //     imei: "123",
      //     //当isCanUsePhoneState=false时,可传入imei信息,穿山甲sdk使用您传入的imei信息
      //     isCanUseWifiState: false,
      //     //是否允许SDK主动使用ACCESS_WIFI_STATE权限
      //     isCanUseWriteExternal: false,
      //     //是否允许SDK主动使用WRITE_EXTERNAL_STORAGE权限
      //     oaid: "111", //开发者可以传入oaid
      //   );
      // }
      await FlutterUnionad.register(
          androidAppId: csjAppId,
          //穿山甲广告 Android appid 必填
          iosAppId: "",
          //穿山甲广告 ios appid 必填
          useTextureView: false,
          //使用TextureView控件播放视频,默认为SurfaceView,当有SurfaceView冲突的场景,可以使用TextureView 选填
          appName: Constant.APP_NAME,
          //appname 必填
          allowShowNotify: true,
          //是否允许sdk展示通知栏提示 选填
          allowShowPageWhenScreenLock: true,
          //是否在锁屏场景支持展示广告落地页 选填
          debug: true,
          //是否显示debug日志
          supportMultiProcess: true,
          //是否支持多进程,true支持 选填
          directDownloadNetworkType: [
            FlutterUnionadNetCode.NETWORK_STATE_4G,
            FlutterUnionadNetCode.NETWORK_STATE_WIFI
          ]); //允许直接下载的网络状态集合 选填
    }
  }
  static Widget loadSplash(
      String? pid, double width, double height, OnAdCallback adCallback) {
    if (pid == null) {
      adCallback(false, "pid为空");
      return Container();
    }
    return FlutterUnionad.splashAdView(
      //是否使用个性化模版  设定widget宽高
      mIsExpress: true,
      //android 开屏广告广告id 必填
      androidCodeId: pid,
      //ios 开屏广告广告id 必填
      iosCodeId: "",
      //是否支持 DeepLink 选填
      supportDeepLink: true,
      // 期望view 宽度 dp 选填 mIsExpress=true必填
      expressViewWidth: width,
      //期望view高度 dp 选填 mIsExpress=true必填
      expressViewHeight: height,
      callBack: FlutterUnionadSplashCallBack(
        onShow: () {
          print("开屏广告显示");
        },
        onClick: () {
          print("开屏广告点击");
        },
        onFail: (error) {
          adCallback(false, error);
        },
        onFinish: () {
          print("开屏广告倒计时结束");
          adCallback(true, "");
        },
        onSkip: () {
          print("开屏广告跳过");
          adCallback(true, "");
        },
        onTimeOut: () {
          print("开屏广告超时");
          adCallback(false, "开屏广告超时");
        },
      ),
    );
  }
  static Widget loadBanner(
      String pid, double width, double height, OnAdCallback callback) {
    return FlutterUnionad.bannerAdView(
      //andrrid banner广告id 必填
      androidCodeId: pid,
      //ios banner广告id 必填
      iosCodeId: "",
      //是否使用个性化模版
      mIsExpress: true,
      //是否支持 DeepLink 选填
      supportDeepLink: true,
      //一次请求广告数量 大于1小于3 必填
      expressAdNum: 3,
      //轮播间隔事件 30-120秒  选填
      expressTime: 30,
      // 期望view 宽度 dp 必填
      expressViewWidth: width,
      //期望view高度 dp 必填
      expressViewHeight: height,
      //广告事件回调 选填
      callBack: FlutterUnionadBannerCallBack(onShow: () {
        print("banner广告加载完成");
      }, onDislike: (message) {
        print("banner不感兴趣 $message");
        callback(false, "banner不感兴趣 $message");
      }, onFail: (error) {
        print("banner广告加载失败 $error");
      }, onClick: () {
        print("banner广告点击");
      }),
    );
  }
  static Widget loadExpress(
      String pid, double width, double height, OnAdCallback callback) {
    return FlutterUnionad.nativeAdView(
      androidCodeId: pid,
      //android 信息流广告id 必填
      iosCodeId: "",
      //ios banner广告id 必填
      supportDeepLink: true,
      //是否支持 DeepLink 选填
      expressViewWidth: width,
      // 期望view 宽度 dp 必填
      expressViewHeight: height,
      //期望view高度 dp 必填
      expressNum: 1,
      mIsExpress: true,
      //一次请求广告数量 大于1小于3 必填
      callBack: FlutterUnionadNativeCallBack(
        onShow: () {
          print("信息流广告显示");
        },
        onFail: (error) {
          print("信息流广告失败 $error");
        },
        onDislike: (message) {
          print("信息流广告不感兴趣 $message");
          callback(false, "信息流广告不感兴趣 $message");
        },
        onClick: () {
          print("信息流广告点击");
        },
      ),
    );
  }
  static loadReward(String pid, OnRewardAdCallback adCallback) async {
    FlutterUnionad.loadRewardVideoAd(
      mIsExpress: true,
      //是否个性化 选填
      androidCodeId: pid,
      //Android 激励视频广告id  必填
      iosCodeId: "",
      //ios 激励视频广告id  必填
      supportDeepLink: true,
      //是否支持 DeepLink 选填
      rewardName: "vip",
      //奖励名称 选填
      rewardAmount: 1,
      //奖励数量 选填
      userID: "",
      //  用户id 选填
      orientation: FlutterUnionadOrientation.VERTICAL,
      //视屏方向 选填
      mediaExtra: null, //扩展参数 选填
    );
    FlutterUnionadStream.initAdStream(
      //激励广告
      flutterUnionadRewardAdCallBack: FlutterUnionadRewardAdCallBack(
        onShow: () {
          print("激励广告显示");
        },
        onClick: () {
          print("激励广告点击");
          adCallback(RewardAdStatus.click, "激励广告点击");
        },
        onFail: (error) {
          print("激励广告失败 $error");
          adCallback(RewardAdStatus.fail, "激励广告失败 $error");
        },
        onClose: () {
          print("激励广告关闭");
          adCallback(RewardAdStatus.close, "激励广告关闭");
        },
        onSkip: () {
          print("激励广告跳过");
        },
        onVerify: (bool isVerify, int rewardAmount, String rewardName,
            int errorCode, String message) {
          adCallback(RewardAdStatus.verify, "获取激励成功");
        },
        onReady: () async {
          adCallback(RewardAdStatus.ready, "激励广告预加载准备就绪");
          //显示激励广告
          await FlutterUnionad.showRewardVideoAd();
        },
        onUnReady: () {
          print("激励广告预加载未准备就绪");
        },
      ),
    );
  }
  static loadInterstitial(String pid, OnAdCallback adCallback) async {
    FlutterUnionad.loadFullScreenVideoAdInteraction(
      androidCodeId: pid, //android 全屏广告id 必填
      iosCodeId: "", //ios 全屏广告id 必填
      supportDeepLink: true, //是否支持 DeepLink 选填
      orientation: FlutterUnionadOrientation.VERTICAL, //视屏方向 选填
    );
    FlutterUnionadStream.initAdStream(
      // 新模板渲染插屏广告回调
      flutterUnionadNewInteractionCallBack:
          FlutterUnionadNewInteractionCallBack(
        onShow: () {
          print("新模板渲染插屏广告显示");
        },
        onSkip: () {
          print("新模板渲染插屏广告跳过");
        },
        onClick: () {
          print("新模板渲染插屏广告点击");
        },
        onFinish: () {
          print("新模板渲染插屏广告结束");
        },
        onFail: (error) {
          print("新模板渲染插屏广告错误 $error");
          adCallback(false, "新模板渲染插屏广告错误 $error");
        },
        onClose: () {
          print("新模板渲染插屏广告关闭");
          adCallback(true, "新模板渲染插屏广告关闭");
        },
        onReady: () async {
          print("新模板渲染插屏广告预加载准备就绪");
          //显示新模板渲染插屏
          await FlutterUnionad.showFullScreenVideoAdInteraction();
        },
        onUnReady: () {
          print("新模板渲染插屏广告预加载未准备就绪");
        },
      ),
    );
  }
}
class GDTAdUtil {
  static Future init() async {
    var gdtAppId = "1200343363";
    //初始化广点通
    if (!StringUtil.isNullOrEmpty(gdtAppId)) {
      await FlutterTencentad.register(
        androidId: gdtAppId, //androidId
        iosId: "", //iosId
        debug: true, //是否显示日志log
      );
    }
  }
  static Widget loadSplash(
      String? pid, double width, double height, OnAdCallback adCallback) {
    return FlutterTencentad.splashAdView(
      //android广告id
      androidId: pid!,
      //ios广告id
      iosId: "",
      ////设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),取值范围为[1500, 5000]ms
      fetchDelay: 3500,
      //广告回调
      callBack: FlutterTencentadSplashCallBack(
        onShow: () {
          print("开屏广告显示");
        },
        onADTick: (time) {
          print("开屏广告倒计时剩余时间 $time");
        },
        onClick: () {
          print("开屏广告点击");
        },
        onClose: () {
          print("开屏广告关闭");
          adCallback(true, "开屏广告关闭");
        },
        onExpose: () {
          print("开屏广告曝光");
        },
        onFail: (code, message) {
          adCallback(false, message);
        },
      ),
    );
  }
  static Widget loadBanner(
      String pid, double width, double height, OnAdCallback callback) {
    return FlutterTencentad.bannerAdView(
      //android广告id
      androidId: pid,
      //ios广告id
      iosId: "",
      //广告宽 单位dp
      viewWidth: width,
      //广告高  单位dp   宽高比应该为6.4:1
      viewHeight: height,
      // 广告回调
      callBack: FlutterTencentadBannerCallBack(
        onShow: () {
          print("Banner广告显示");
        },
        onFail: (code, message) {
          print("Banner广告错误 $code $message");
          callback(false, "Banner广告错误  $code $message");
        },
        onClose: () {
          print("Banner广告关闭");
          callback(true, "Banner广告关闭");
        },
        onExpose: () {
          print("Banner广告曝光");
        },
        onClick: () {
          print("Banner广告点击");
        },
      ),
    );
  }
  static Widget loadExpress(
      String pid, double width, double height, OnAdCallback callback) {
    return FlutterTencentad.expressAdView(
        //android广告id
        androidId: pid,
        //ios广告id
        iosId: "",
        //广告宽 单位dp
        viewWidth: width.toInt(),
        //广告高  单位dp
        viewHeight: height.toInt(),
        //回调事件
        callBack: FlutterTencentadExpressCallBack(
          onShow: () {
            print("动态信息流广告显示");
          },
          onFail: (code, message) {
            print("动态信息流广告错误 $code $message");
          },
          onClose: () {
            print("动态信息流广告关闭");
          },
          onExpose: () {
            print("动态信息流广告曝光");
          },
          onClick: () {
            print("动态信息流广告点击");
          },
        ));
  }
  static loadReward(String pid, OnRewardAdCallback adCallback) async {
    await FlutterTencentad.loadRewardVideoAd(
        //android广告id
        androidId: pid,
        //ios广告id
        iosId: "",
        //用户id
        userID: "",
        //奖励
        rewardName: "VIP",
        //奖励数
        rewardAmount: 1,
        //扩展参数 服务器回调使用
        customData: "");
    FlutterTencentAdStream.initAdStream(
      //激励广告
      flutterTencentadRewardCallBack:
          FlutterTencentadRewardCallBack(onShow: () {
        print("激励广告显示");
      }, onClick: () {
        print("激励广告点击");
        adCallback(RewardAdStatus.click, "激励广告点击");
      }, onFail: (code, message) {
        print("激励广告失败 $code $message");
        adCallback(RewardAdStatus.fail, "激励广告失败");
      }, onClose: () {
        print("激励广告关闭");
        adCallback(RewardAdStatus.close, "激励广告关闭");
      }, onReady: () async {
        print("激励广告预加载准备就绪");
        adCallback(RewardAdStatus.ready, "激励广告预加载准备就绪");
        await FlutterTencentad.showRewardVideoAd();
      }, onUnReady: () {
        print("激励广告预加载未准备就绪");
      }, onVerify: (transId, rewardName, rewardAmount) {
        print("激励广告奖励  $transId   $rewardName   $rewardAmount");
        adCallback(RewardAdStatus.verify, "激励广告奖励");
      }, onFinish: () {
        print("激励广告完成");
      }),
    );
  }
  static loadInterstitial(String pid, OnAdCallback adCallback) async {
    await FlutterTencentad.loadUnifiedInterstitialAD(
      //android广告id
      androidId: pid,
      //ios广告id
      iosId: "",
      //是否全屏
      isFullScreen: false,
    );
    FlutterTencentAdStream.initAdStream(
      flutterTencentadInteractionCallBack: FlutterTencentadInteractionCallBack(
        onShow: () {
          print("插屏广告显示");
        },
        onClick: () {
          print("插屏广告点击");
        },
        onFail: (code, message) {
          print("插屏广告失败 $code $message");
          adCallback(false, "插屏广告失败 $code $message");
        },
        onClose: () {
          print("插屏广告关闭");
          adCallback(true, "插屏广告关闭");
        },
        onReady: () async {
          print("插屏广告预加载准备就绪");
          await FlutterTencentad.showUnifiedInterstitialAD();
        },
        onUnReady: () {
          print("插屏广告预加载未准备就绪");
        },
      ),
    );
  }
}
class AdPosition {
  //开屏
  static String splash = "splash";
  //首页插屏
  static String homeInterstitial = "homeInterstitial";
  //我的页面原生
  static String mineExpress = "mineExpress";
  //搜索页面原生
  static String searchExpress = "searchExpress";
  //搜索结果banner
  static String searchResultBanner = "searchResultBanner";
  //轨迹分享页插屏
  static String travelShareInterstitial = "travelShareInterstitial";
  //会员激励视频
  static String vipReward = "vipReward";
}
src/main/resources/code/flutter/lib/utils/app_util.dart
New file
@@ -0,0 +1,77 @@
import 'dart:io';
import 'package:device_info/device_info.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:fluwx_no_pay/fluwx_no_pay.dart';
import 'package:jpush_flutter/jpush_flutter.dart';
import 'package:package_info/package_info.dart';
import 'ad_util.dart';
import 'global.dart';
import 'push_util.dart';
class AppUtil {
  static final JPush _jpush = JPush();
  static bool _inited = false;
  //初始化应用
  static Future<bool> initApp(BuildContext context) async {
    if (_inited) {
      return true;
    }
    _inited = true;
    print("initApp");
    await registerWxApi(
        appId: "wxd930ea5d5a228f5f",
        universalLink: "https://your.univerallink.com/link/");
    //初始化广告
    await AdUtil.init();
    //初始化本地应用
    await _initNativeApp();
    //初始化极光
    try {
      PushUtil.init(context);
    } catch (e) {}
    //初始化版本
    if (Platform.isAndroid) {
      DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
      AndroidDeviceInfo _androidInfo = await deviceInfo.androidInfo;
      Global.androidSDK = _androidInfo.version.sdkInt;
    }
    // //初始化阿里云授权登录
    // await LoginPage.messageChannel.send({
    //   "method": "init",
    //   "secret": Constant.ALIYUN_AUTH_SECRETINFO,
    //   "privacy": Constant.PRIVACY_URL,
    //   "protocol": Constant.PROTOCOL_URL
    // }) as Map;
    return true;
  }
  //本地应用初始化
  static _initNativeApp() async {
    if (Platform.isAndroid) {
      const platform = MethodChannel("com.yeshi.location/init"); //分析1
      try {
        await platform.invokeMethod("initApp"); //分析2
      } on PlatformException catch (e) {
        print(e.toString());
      }
      //填充utdid
      await Global.loadUtdId();
      //填充channel
      await Global.loadChannel();
    }
  }
  static Future<int> getVersionCode() async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    return int.parse(packageInfo.buildNumber);
  }
}
src/main/resources/code/flutter/lib/utils/cache_util.dart
New file
@@ -0,0 +1,57 @@
import 'dart:io';
import 'package:path_provider/path_provider.dart';
/// 缓存管理类
/// ./lib/utils/cache_util.dart
class CacheUtil {
  /// 获取缓存大小
  static Future<int> total() async {
    Directory tempDir = await getTemporaryDirectory();
    if (tempDir == null) return 0;
    int total = await _reduce(tempDir);
    return total;
  }
  /// 清除缓存
  static Future<void> clear() async {
    Directory tempDir = await getTemporaryDirectory();
    if (tempDir == null) return;
    await _delete(tempDir);
  }
  /// 递归缓存目录,计算缓存大小
  static Future<int> _reduce(final FileSystemEntity file) async {
    /// 如果是一个文件,则直接返回文件大小
    if (file is File) {
      int length = await file.length();
      return length;
    }
    /// 如果是目录,则遍历目录并累计大小
    if (file is Directory) {
      final List<FileSystemEntity> children = file.listSync();
      int total = 0;
      if (children != null && children.isNotEmpty)
        for (final FileSystemEntity child in children)
          total += await _reduce(child);
      return total;
    }
    return 0;
  }
  /// 递归删除缓存目录和文件
  static Future<void> _delete(FileSystemEntity file) async {
    if (file is Directory) {
      final List<FileSystemEntity> children = file.listSync();
      for (final FileSystemEntity child in children) {
        await _delete(child);
      }
    } else {
      await file.delete();
    }
  }
}
src/main/resources/code/flutter/lib/utils/config_util.dart
New file
@@ -0,0 +1,55 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import '../api/http.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ConfigUtil {
  ///保存配置信息
  static void saveConfig(Map<String, dynamic> map) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString("config_value", jsonEncode(map));
  }
  static Future<String?> getConfig(String key) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? result = prefs.getString("config_value");
    if (result != null) {
      Map<String, dynamic> map = jsonDecode(result);
      return map[key];
    } else {
      //重新请求
      ConfigApiUtil.getConfig().then((value) {
        if (value == null) {
          return;
        }
        if (value["code"] == 0) {
          saveConfig(value["data"]);
        }
      });
    }
    return null;
  }
}
class ConfigKey {
  //客服
  static const String kefu = "kefu";
  //教程
  static const String course = "course";
  //注销
  static const String unRegister = "unRegister";
  //隐私投诉
  static const String privacyComplain = "privacyComplain";
  //会员链接
  static const String vipLink = "vipLink";
  //三方SDK链接
  static const String sdkList = "sdkList";
}
enum SharePlatform { wx, wxcircle, qq, qqzone, sina }
src/main/resources/code/flutter/lib/utils/encrypt_util.dart
New file
@@ -0,0 +1,8 @@
import 'dart:convert';
import 'package:crypto/crypto.dart';
class EncryptUtil {
  static String MD5(String data) {
    return md5.convert(utf8.encode(data)).toString();
  }
}
src/main/resources/code/flutter/lib/utils/event_bus_util.dart
New file
@@ -0,0 +1,10 @@
import 'package:event_bus/event_bus.dart';
EventBus eventBus = EventBus();
class LoginEventBus {
  final bool isLogin;
  LoginEventBus(this.isLogin);
}
src/main/resources/code/flutter/lib/utils/global.dart
New file
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
//全局跳转
final GlobalKey<NavigatorState> navigatorKey =  GlobalKey<NavigatorState>();
class Global {
  static const messageChannel =
      BasicMessageChannel('DeviceUtil', StandardMessageCodec());
  static String? utdId;
  static String? channel;
  //android的版本
  static int? androidSDK;
  static Future loadUtdId() async {
    String? value =
        await messageChannel.send({"method": "getUtdid"}) as String?;
    utdId = value;
  }
  static Future loadChannel() async {
    String? value =
    await messageChannel.send({"method": "getChannel"}) as String?;
    channel = value;
  }
}
src/main/resources/code/flutter/lib/utils/jsinterface.dart
New file
@@ -0,0 +1,239 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:fluttertoast/fluttertoast.dart';
import '../api/http.dart' as http;
import '../utils/ad_util.dart';
import '../utils/encrypt_util.dart';
import '../utils/permission_util.dart';
import '../utils/share_utils.dart';
import '../utils/string_util.dart';
import '../utils/ui_constant.dart';
import '../utils/ui_utils.dart';
import '../utils/user_util.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:webview_flutter/platform_interface.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:path_provider/path_provider.dart';
import 'config_util.dart';
class JavascriptInterface {
  final BuildContext context;
  final WebViewController? _controller;
  JavascriptInterface(
      BuildContext this.context, WebViewController? this._controller);
  Set<JavascriptChannel> getInterfaces() {
    List<JavascriptChannel> list = [];
    list.add(JavascriptChannel(
        name: 'yestv',
        onMessageReceived: (JavascriptMessage message) {
          print("onMessageReceived");
          var data = jsonDecode(message.message);
          String method = data["method"];
          var params = data["params"];
          String? _callback = data["callback"];
          switch (method) {
            case "toast":
              toast(params);
              break;
            case "copyText":
              copyText(params);
              break;
            case "getUid":
              getUid(params, _callback);
              break;
            case "getAppName":
              getAppName(_callback);
              break;
            case "getRequestBaseParams":
              getRequestBaseParams(params, _callback);
              break;
            case "showRewardVideoAd":
              showRewardVideoAd(_callback);
              break;
            case "showLoading":
              showLoading();
              break;
            case "hideLoading":
              hideLoading();
              break;
            case "finishPage":
              finishPage();
              break;
            case "saveImg":
              String url = params["url"];
              saveImg(url);
              break;
            case "shareImg":
              String url = params["url"];
              String type = params["type"];
              shareImg(url, int.parse(type));
              break;
          }
        }));
    return list.toSet();
  }
  callback(String method, var params, {bool finish = true}) {
    _controller!.runJavascript("$method('$params')");
    if (finish) {
      _controller!.runJavascript("delete $method");
    }
  }
  //获取用户ID
  getUid(var params, String? callbackName) {
    if (callbackName != null) {
      UserUtil.getUid().then((value) {
        callback(callbackName, value != null ? value.toString() : "");
      });
    }
  }
  //获取用户ID
  getAppName(String? callbackName) {
    if (callbackName != null) {
        callback(callbackName, Constant.APP_NAME);
    }
  }
  //toast
  toast(params) {
    if (params != null && params["msg"] != null) {
      Fluttertoast.showToast(msg: params["msg"]);
    }
  }
  copyText(params) {
    if (params != null && params["content"] != null) {
      Clipboard.setData(ClipboardData(text: params["content"]));
    }
  }
  //获取基本的网络请求参数
  getRequestBaseParams(var params, String? callbackName) {
    var ps = {};
    if (params != null) {
      ps.addAll(params);
    }
    http.HttpUtil.getBaseParams(params).then((value) {
      String result = jsonEncode(value);
      if (callbackName != null) {
        callback(callbackName, result);
      }
    });
  }
  //展示激励视频
  showRewardVideoAd(String? callbackName) {
    AdUtil.getAdInfo(AdPosition.vipReward).then((value) {
      AdUtil.loadReward(value, (status, msg) {
        switch (status) {
          case RewardAdStatus.verify:
            callback(callbackName!, 3, finish: false);
            break;
          case RewardAdStatus.ready:
            callback(callbackName!, 1, finish: false);
            break;
          case RewardAdStatus.close:
            callback(callbackName!, 10, finish: true);
            break;
          case RewardAdStatus.click:
            callback(callbackName!, 2, finish: false);
            break;
          case RewardAdStatus.fail:
            callback(callbackName!, 0, finish: true);
            break;
        }
      });
    });
  }
  showLoading() {
    http.showLoading(context);
  }
  hideLoading() {
    Navigator.of(context).pop();
  }
  //结束页面
  finishPage() {
    Navigator.of(context).pop();
  }
  Future<bool> _dowloadImg(String url, String path) async {
    PermissionStatus status =
        await PermissionUtil.openPermission(Permission.storage, force: true);
    if (status != PermissionStatus.granted) {
      return false;
    }
    //下载图片
    Dio dio = Dio();
    //设置连接超时时间
    dio.options.connectTimeout = 20000;
    //设置数据接收超时时间
    dio.options.receiveTimeout = 20000;
    Response response;
    try {
      response = await dio.download(url, path);
      if (response.statusCode == 200) {
        return true;
      } else {
        return false;
      }
    } catch (e) {
      ToastUtil.toast("网络连接失败");
      return false;
    }
  }
  //保存图片
  saveImg(String url) {
    getExternalStorageDirectory().then((value) {
      if (value == null) {
        ToastUtil.toast("获取缓存目录失败");
        return;
      }
      String doc = value.path;
      String path = doc + "/" + EncryptUtil.MD5(url) + ".png";
      _dowloadImg(url, path).then((value) {
        if (value) {
          ToastUtil.toast("保存成功");
        }
      });
    });
  }
  ///分享图片
  ///type: 1-微信  2-qq 3-新浪
  shareImg(String url, int type) {
    getTemporaryDirectory().then((value) {
      String path = value.path + "/" + EncryptUtil.MD5(url) + ".png";
      _dowloadImg(url, path).then((value) {
        if (value) {
          //开始分享
          switch (type) {
            case 1:
              ShareUtil.shareImg(context, File(path), SharePlatform.wx);
              break;
            case 2:
              ShareUtil.shareImg(context, File(path), SharePlatform.qq);
              break;
            case 3:
              ShareUtil.shareImg(context, File(path), SharePlatform.sina);
              break;
          }
        }
      });
    });
  }
}
src/main/resources/code/flutter/lib/utils/pageutils.dart
New file
@@ -0,0 +1,95 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'global.dart';
typedef PageDataLisener = void Function(dynamic data);
//滑动效果
class CustomRouteSlide extends PageRouteBuilder {
  final Widget widget;
  CustomRouteSlide(this.widget)
      : super(
            transitionDuration: const Duration(milliseconds: 500),
            pageBuilder: (BuildContext context, Animation<double> animation1,
                Animation<double> animation2) {
              return widget;
            },
            transitionsBuilder: (BuildContext context,
                Animation<double> animation1,
                Animation<double> animation2,
                Widget child) {
              return SlideTransition(
                position: Tween<Offset>(
                        begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0))
                    .animate(CurvedAnimation(
                        parent: animation1, curve: Curves.fastOutSlowIn)),
                child: child,
              );
            });
}
class NavigatorUtil {
  // static void navigateToNextPage(BuildContext context, PageRoute route,
  //     PageDataLisener? dataLisener) async {
  //   final result = await Navigator.of(context).push(route);
  //   dataLisener!(result);
  // }
  static void navigateToNextPage(
      BuildContext context, Widget page, PageDataLisener? dataLisener) async {
    final result =
        await Navigator.of(context).push(CupertinoPageRoute(builder: (context) {
      return page;
    }));
    dataLisener!(result);
  }
  static void navigateToNextPagePush(Widget page) {
    navigatorKey.currentState!.push(
        CupertinoPageRoute (builder: (BuildContext context) => page));
  }
  static void navigateToNextPageWithFinish(
      BuildContext context, PageRoute route) {
    Navigator.of(context).pushReplacement(route);
  }
}
class KeepAliveWrapper extends StatefulWidget {
  const KeepAliveWrapper({
    Key? key,
    this.keepAlive = true,
    required this.child,
  }) : super(key: key);
  final bool keepAlive;
  final Widget child;
  @override
  _KeepAliveWrapperState createState() => _KeepAliveWrapperState();
}
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return widget.child;
  }
  @override
  void didUpdateWidget(covariant KeepAliveWrapper oldWidget) {
    if (oldWidget.keepAlive != widget.keepAlive) {
      // keepAlive 状态需要更新,实现在 AutomaticKeepAliveClientMixin 中
      updateKeepAlive();
    }
    super.didUpdateWidget(oldWidget);
  }
  @override
  bool get wantKeepAlive => widget.keepAlive;
}
src/main/resources/code/flutter/lib/utils/permission_util.dart
New file
@@ -0,0 +1,150 @@
import 'dart:convert';
import 'dart:io';
import '../utils/global.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'event_bus_util.dart';
class PermissionUtil {
  static var deniedSets = Set();
  static Permission getLocationPermission() {
    if (Platform.isAndroid) {
      //获取系统版本
      if (Global.androidSDK != null && Global.androidSDK! < 29) {
        return Permission.locationAlways;
      } else {
        return Permission.location;
      }
    } else {
      return Permission.locationAlways;
    }
  }
  static Future _loadDeniedPermissions() async {
    //加载
    SharedPreferences prefs = await SharedPreferences.getInstance();
    List<String>? list = prefs.getStringList("permission_delay_list");
    deniedSets.clear();
    if (list != null) {
      deniedSets.addAll(list);
    }
    print(jsonEncode(list));
  }
  static Future _denyPermission(Permission permission) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    List<String>? list = prefs.getStringList("permission_delay_list");
    list ??= [];
    bool hasAdd = false;
    list.forEach((element) {
      if (element == permission.value.toString()) {
        hasAdd = true;
      }
    });
    if (!hasAdd) {
      list.add(permission.value.toString());
    }
    await prefs.setStringList("permission_delay_list", list);
  }
  static Future _removeDenyPermission(Permission permission) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    List<String>? list = prefs.getStringList("permission_delay_list");
    list ??= [];
    for (int i = 0; i < list.length; i++) {
      if (list[i] == permission.value.toString()) {
        list.removeAt(i);
        i--;
      }
    }
    await prefs.setStringList("permission_delay_list", list);
  }
  ///打开应用设置
  static openAppSetting() async {
    await openAppSettings();
  }
  ///打开权限,
  ///force:强制打开,权限被拒绝后记录
  static Future<PermissionStatus> openPermission(Permission permission,
      {force: false}) async {
    await _loadDeniedPermissions();
    PermissionStatus status = await permission.status;
    PermissionStatus? resultStatus;
    switch (status) {
      //Android授权
      case PermissionStatus.granted:
        resultStatus = status;
        break;
      //Android拒绝
      case PermissionStatus.denied:
        if (deniedSets.contains(permission.value.toString()) && !force) {
          resultStatus = PermissionStatus.denied;
        } else {
          resultStatus = await permission.request();
        }
        break;
      //Android禁止后不再提示
      case PermissionStatus.permanentlyDenied:
        if (deniedSets.contains(permission.value.toString()) && !force) {
          resultStatus = PermissionStatus.permanentlyDenied;
        } else {
          bool success = await openAppSettings();
          resultStatus = await permission.status;
        }
        break;
      //IOS
      case PermissionStatus.limited:
        if (deniedSets.contains(permission.value.toString()) && !force) {
          resultStatus = PermissionStatus.limited;
        } else {
          resultStatus = await permission.request();
        }
        break;
      //IOS
      case PermissionStatus.restricted:
        if (deniedSets.contains(permission.value.toString()) && !force) {
          resultStatus = PermissionStatus.restricted;
        } else {
          resultStatus = await permission.request();
        }
        break;
    }
    if (resultStatus == PermissionStatus.granted) {
      _removeDenyPermission(permission);
    } else {
      _denyPermission(permission);
    }
    return resultStatus;
  }
  ///批量打开权限
  static openPermissions(List<Permission> permissions, {force: true}) async {
    await _loadDeniedPermissions();
    List<Permission> requestPS = [];
    permissions.forEach((element) {
      if (!deniedSets.contains(element.value.toString())) {
        requestPS.add(element);
      }
    });
    if (requestPS.isNotEmpty) {
      await requestPS.request();
    }
  }
  ///关闭权限
  static Future<PermissionStatus> closePermission(Permission permission) async {
    bool success = await openAppSettings();
    return await permission.status;
  }
}
src/main/resources/code/flutter/lib/utils/push_util.dart
New file
@@ -0,0 +1,89 @@
import 'dart:convert';
import 'dart:io';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:fluwx_no_pay/fluwx_no_pay.dart';
import 'package:flutter/services.dart';
import 'package:jpush_flutter/jpush_flutter.dart';
import '../api/http.dart';
import '../model/user/user_info.dart';
import '../utils/event_bus_util.dart';
import '../utils/pageutils.dart';
import '../utils/user_util.dart';
import 'global.dart';
class PushUtil {
  static final JPush _jpush = JPush();
  static init(BuildContext context) async {
    try {
      _jpush.addEventHandler(
          onReceiveNotification: (Map<String, dynamic> message) async {
        print("flutter onReceiveNotification: $message");
      }, onOpenNotification: (Map<String, dynamic> message) async {
        var extra = message["extras"]["cn.jpush.android.EXTRA"];
        extra = jsonDecode(extra);
        // //打开页面
        // var type = extra["type"];
        //
        // if (type == "sos") {
        //   //SOS
        //   NavigatorUtil.navigateToNextPagePush(SOSPage(title: ""));
        // } else if (type == "locationInvite") {
        //   //请求定位
        //   eventBus.fire(LocationInviteEventBus());
        // }
      }, onReceiveMessage: (Map<String, dynamic> message) async {
        var data = jsonDecode(message["message"]);
        print("flutter onReceiveMessage: $data");
        var type = data["type"];
        // if (type == "sos") {
        //   //SOS
        //   NavigatorUtil.navigateToNextPagePush(SOSPage(title: ""));
        // } else if (type == "locationInvite") {
        //     eventBus.fire(LocationInviteEventBus());
        // }
      }, onReceiveNotificationAuthorization:
              (Map<String, dynamic> message) async {
        print("flutter onReceiveNotificationAuthorization: $message");
      });
    } on PlatformException {}
    _jpush.setup(
      appKey: "987d3d50f209994fa522d001", //你自己应用的 AppKey
      channel: "developer-default",
      production: false,
      debug: true,
    );
    _jpush.applyPushAuthority(
        NotificationSettingsIOS(sound: true, alert: true, badge: true));
    // Platform messages may fail, so we use a try/catch PlatformException.
    _jpush.getRegistrationID().then((rid) {
      print("flutter get registration id : $rid");
      UserApiUtil.uploadPushRegId(context, rid);
    });
    //如果登录了就设置用户的uid
    bool isLogin = await UserUtil.isLogin();
    if (isLogin) {
      UserInfo? user = await UserUtil.getUserInfo();
      setAlias(user!.id!.toString());
    }
  }
  ///添加alias
  static Future setAlias(String alias) async {
    try {
      await _jpush.setAlias(alias);
    } catch (e) {}
  }
  //删除alias
  static Future removeAlias() async {
    await _jpush.deleteAlias();
  }
}
src/main/resources/code/flutter/lib/utils/setting_util.dart
New file
@@ -0,0 +1,46 @@
import 'package:shared_preferences/shared_preferences.dart';
class SettingUtil {
  //设置推送
  static Future<bool> setPush(bool enable) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return await prefs.setBool("setting_push", enable);
  }
  ///是否允许推送
  static Future<bool> isEnablePush() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool? result = prefs.getBool("setting_push");
    result ??= true;
    return result;
  }
  //设置推荐广告
  static Future<bool> setRecommendAd(bool enable) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return await prefs.setBool("setting_recommend_ad", enable);
  }
  ///是否允许推荐广告
  static Future<bool> isEnableRecommendAd() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool? result = prefs.getBool("setting_recommend_ad");
    result ??= true;
    return result;
  }
  //设置推荐广告
  static Future<bool> setLocationSpan(int second) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return await prefs.setInt("setting_location_span", second);
  }
  ///是否允许推荐广告
  static Future<int> getLocationSpan() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    int? result = prefs.getInt("setting_location_span");
    result ??= 30;
    return result;
  }
}
src/main/resources/code/flutter/lib/utils/share_utils.dart
New file
@@ -0,0 +1,40 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:share_plus/share_plus.dart';
import 'config_util.dart';
class ShareUtil {
  static shareImg(
      BuildContext context, File f, SharePlatform sharePlatform) async {
    if (Platform.isAndroid) {
      const platform = MethodChannel("com.yeshi.location/share"); //分析1
      bool result = false;
      try {
        var params = {
          "path": f.path,
          "platform": sharePlatform.runtimeType.toString()
        };
        switch (sharePlatform) {
          case SharePlatform.qq:
            params["platform"] = "qq";
            break;
          case SharePlatform.wx:
            params["platform"] = "wx";
            break;
          case SharePlatform.sina:
            params["platform"] = "sina";
            break;
        }
        result = await platform.invokeMethod("shareImg", params); //分析2
      } on PlatformException catch (e) {
        print(e.toString());
      }
    } else {
      Share.shareFiles([f.path]);
    }
  }
}
src/main/resources/code/flutter/lib/utils/string_util.dart
New file
@@ -0,0 +1,13 @@
class StringUtil {
  //是否为电话号码
  static bool isMobile(String str) {
    return RegExp(
            '^((13[0-9])|(15[^4])|(166)|(17[0-8])|(18[0-9])|(19[8-9])|(147,145))\\d{8}\$')
        .hasMatch(str);
  }
  static bool isNullOrEmpty(String? str) {
    return str==null|| str.isEmpty || str.trim().isEmpty;
  }
}
src/main/resources/code/flutter/lib/utils/ui_constant.dart
New file
@@ -0,0 +1,40 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
//滑动效果
class ColorConstant {
  static const Color theme = Color(0xFF0078FF);//Color(0xFF0E95FE);
  static const Color title = Color(0xFF333333);
}
class Constant {
  static const String APP_NAME =
      "定位追踪轨迹";
  //阿里云授权登录
  static const String ALIYUN_AUTH_SECRETINFO =
      "v+dQBemz/CZaLI0YP/A5AxxG2YgF7IvP+RNzRkmOGln1bbd7tcMt7uvqt8dvb9ekawjGbvSZ6Y/N9WT0kpUb6lrkS11BxfhCpXtuxmOxei97xP3l5Hd8PVqPv2jPC8uVDRhl6kaAqf/6I1gwL1d7am+8w1sGkYnZ3UEgd9ljDBKjeRbbpp+KEzLiqnKWYDNqMLSRdU0BmzTSGqtkM5c1TYOZgx68NxwE2oM9VzcjQEeFP0yiQatMyNIQ5mJjbyU3zi9qiyMQaeTLHeACvqZ2XCYQBbAeqJh6DPrhIHGlfGc=";
  //隐私政策链接
  static const String PRIVACY_URL =
      "http://web.location.izzql.com/privacy.html";
  //用户协议链接
  static const String PROTOCOL_URL =
      "http://web.location.izzql.com/user_protocol.html";
  //微信
  static const String WX_APPID = "wxd930ea5d5a228f5f";
  static const String WX_UNIVERSAL_LINK = "https://your.univerallink.com/link/";
  static const String APP_DOWNLOAD_LINK =
      "https://a.app.qq.com/o/simple.jsp?pkgname=com.dw.zzql";
  static const String MAP_LINK =
      "http://web.location.izzql.com/map/map.html";
}
src/main/resources/code/flutter/lib/utils/ui_utils.dart
New file
@@ -0,0 +1,28 @@
import 'package:flutter/cupertino.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter/material.dart';
class ToastUtil {
  static toast(String text) {
    Fluttertoast.showToast(msg: text);
  }
}
class DialogUtil {
  static Future<dynamic> showDialog(BuildContext context, Dialog dialog) async {
    return await showGeneralDialog(
        context: context,
        pageBuilder: (BuildContext buildContext, Animation<double> animation,
            Animation<double> secondaryAnimation) {
          return dialog;
        });
  }
}
class DimenUtil {
  //获取像素比
  static double getPixelRatio(BuildContext context) {
    MediaQueryData mediaQuery = MediaQuery.of(context);
    return mediaQuery.devicePixelRatio;
  }
}
src/main/resources/code/flutter/lib/utils/user_util.dart
New file
@@ -0,0 +1,109 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx;
import '../api/http.dart';
import '../model/user/user_info.dart';
import '../utils/event_bus_util.dart';
import '../utils/string_util.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'push_util.dart';
Timer? locationTimer;
class UserUtil {
  static const _loginMessageChannel =
      BasicMessageChannel('ThirdLogin', StandardMessageCodec());
  //是否同意了用户协议
  static Future<bool> isAgreeProtocol() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool? agree = prefs.getBool("agree_protocol");
    if (agree == null) {
      return false;
    }
    return agree;
  }
  //设置已同意用户协议
  static Future<bool> setAgreeProtocol() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.setBool("agree_protocol", true);
  }
  ///微信登录
  static void loginWX() async {
    fluwx
        .sendWeChatAuth(scope: "snsapi_userinfo", state: "wechat_sdk_demo_test")
        .then((value) {});
  }
  ///QQ登录
  static Future<Map> loginQQ() async {
    Map value = await _loginMessageChannel.send({"method": "loginQQ"}) as Map;
    return value;
  }
  //是否已经登录
  static Future<bool> isLogin() async {
    UserInfo? user = await getUserInfo();
    return user != null;
  }
  //用户信息
  static Future<UserInfo?> getUserInfo() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? result = await prefs.getString("user_info");
    if (StringUtil.isNullOrEmpty(result)) {
      return null;
    } else {
      return UserInfo.fromJson(jsonDecode(result!));
    }
  }
  static Future updateUserInfo(BuildContext context) async {
    int? uid = await getUid();
    if (uid == null) {
      return;
    }
    Map<String, dynamic>? result = await UserApiUtil.getUserInfo(context, uid);
    var code = result!["code"];
    if (code == 0) {
      UserInfo user = UserInfo.fromJson(result["data"]);
      //保存用户信息
      UserUtil.setUserInfo(user);
    } else if (code == 80001 || code == 80002) {
      await logout();
    }
  }
  static Future<int?> getUid() async {
    UserInfo? user = await getUserInfo();
    if (user != null) {
      return user.id;
    }
    return null;
  }
  static Future setUserInfo(UserInfo user) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString("user_info", jsonEncode(user));
  }
  //退出登录
  static logout() async {
    await _logout();
    await PushUtil.removeAlias();
    eventBus.fire(LoginEventBus(false));
  }
  static _logout() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.remove("user_info");
  }
}
src/main/resources/code/flutter/pubspec.lock
New file
@@ -0,0 +1,691 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
  async:
    dependency: transitive
    description:
      name: async
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.8.1"
  boolean_selector:
    dependency: transitive
    description:
      name: boolean_selector
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.0"
  characters:
    dependency: transitive
    description:
      name: characters
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.1.0"
  charcode:
    dependency: transitive
    description:
      name: charcode
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.3.1"
  clock:
    dependency: transitive
    description:
      name: clock
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.1.0"
  collection:
    dependency: transitive
    description:
      name: collection
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.15.0"
  crypto:
    dependency: "direct dev"
    description:
      name: crypto
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "3.0.1"
  csslib:
    dependency: transitive
    description:
      name: csslib
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.17.1"
  cupertino_icons:
    dependency: "direct main"
    description:
      name: cupertino_icons
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.0.4"
  date_format:
    dependency: "direct dev"
    description:
      name: date_format
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.5"
  device_info:
    dependency: "direct dev"
    description:
      name: device_info
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.3"
  device_info_platform_interface:
    dependency: transitive
    description:
      name: device_info_platform_interface
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.1"
  dio:
    dependency: "direct dev"
    description:
      name: dio
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "4.0.4"
  event_bus:
    dependency: "direct dev"
    description:
      name: event_bus
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.0"
  fake_async:
    dependency: transitive
    description:
      name: fake_async
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.2.0"
  ffi:
    dependency: transitive
    description:
      name: ffi
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.1.2"
  file:
    dependency: transitive
    description:
      name: file
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "6.1.2"
  flutter:
    dependency: "direct main"
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_datetime_picker:
    dependency: "direct dev"
    description:
      name: flutter_datetime_picker
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.5.1"
  flutter_lints:
    dependency: "direct dev"
    description:
      name: flutter_lints
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.0.4"
  flutter_page_indicator:
    dependency: transitive
    description:
      name: flutter_page_indicator
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.0.3"
  flutter_spinkit:
    dependency: "direct dev"
    description:
      name: flutter_spinkit
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "5.1.0"
  flutter_swiper:
    dependency: "direct dev"
    description:
      name: flutter_swiper
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.1.6"
  flutter_tencentad:
    dependency: "direct dev"
    description:
      name: flutter_tencentad
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.1.4"
  flutter_test:
    dependency: "direct dev"
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_unionad:
    dependency: "direct dev"
    description:
      name: flutter_unionad
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.2.2"
  flutter_web_plugins:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_widget_from_html_core:
    dependency: "direct dev"
    description:
      name: flutter_widget_from_html_core
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.8.4"
  fluttertoast:
    dependency: "direct dev"
    description:
      name: fluttertoast
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "8.0.8"
  fluwx_no_pay:
    dependency: "direct dev"
    description:
      name: fluwx_no_pay
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "3.6.1+5"
  fwfh_text_style:
    dependency: transitive
    description:
      name: fwfh_text_style
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.5.1"
  html:
    dependency: transitive
    description:
      name: html
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.15.0"
  http_parser:
    dependency: transitive
    description:
      name: http_parser
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "4.0.0"
  jpush_flutter:
    dependency: "direct dev"
    description:
      name: jpush_flutter
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.2.2"
  js:
    dependency: transitive
    description:
      name: js
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.6.3"
  launch_review:
    dependency: "direct dev"
    description:
      name: launch_review
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "3.0.1"
  lints:
    dependency: transitive
    description:
      name: lints
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.0.1"
  matcher:
    dependency: transitive
    description:
      name: matcher
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.12.10"
  meta:
    dependency: transitive
    description:
      name: meta
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.7.0"
  mime:
    dependency: transitive
    description:
      name: mime
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.0.1"
  package_info:
    dependency: "direct dev"
    description:
      name: package_info
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.2"
  path:
    dependency: transitive
    description:
      name: path
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.8.0"
  path_provider:
    dependency: "direct dev"
    description:
      name: path_provider
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.8"
  path_provider_android:
    dependency: transitive
    description:
      name: path_provider_android
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.11"
  path_provider_ios:
    dependency: transitive
    description:
      name: path_provider_ios
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.7"
  path_provider_linux:
    dependency: transitive
    description:
      name: path_provider_linux
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.5"
  path_provider_macos:
    dependency: transitive
    description:
      name: path_provider_macos
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.5"
  path_provider_platform_interface:
    dependency: transitive
    description:
      name: path_provider_platform_interface
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.3"
  path_provider_windows:
    dependency: transitive
    description:
      name: path_provider_windows
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.5"
  permission_handler:
    dependency: "direct dev"
    description:
      name: permission_handler
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "8.3.0"
  permission_handler_platform_interface:
    dependency: transitive
    description:
      name: permission_handler_platform_interface
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "3.7.0"
  platform:
    dependency: transitive
    description:
      name: platform
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "3.1.0"
  plugin_platform_interface:
    dependency: transitive
    description:
      name: plugin_platform_interface
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.2"
  process:
    dependency: transitive
    description:
      name: process
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "4.2.4"
  pull_to_refresh:
    dependency: "direct dev"
    description:
      name: pull_to_refresh
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.0"
  qr:
    dependency: transitive
    description:
      name: qr
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.0"
  qr_flutter:
    dependency: "direct dev"
    description:
      name: qr_flutter
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "4.0.0"
  screenshot:
    dependency: "direct dev"
    description:
      name: screenshot
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.2.3"
  share_plus:
    dependency: "direct dev"
    description:
      name: share_plus
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "3.0.4"
  share_plus_linux:
    dependency: transitive
    description:
      name: share_plus_linux
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.4"
  share_plus_macos:
    dependency: transitive
    description:
      name: share_plus_macos
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.2"
  share_plus_platform_interface:
    dependency: transitive
    description:
      name: share_plus_platform_interface
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.1"
  share_plus_web:
    dependency: transitive
    description:
      name: share_plus_web
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.4"
  share_plus_windows:
    dependency: transitive
    description:
      name: share_plus_windows
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.3"
  shared_preferences:
    dependency: "direct dev"
    description:
      name: shared_preferences
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.12"
  shared_preferences_android:
    dependency: transitive
    description:
      name: shared_preferences_android
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.10"
  shared_preferences_ios:
    dependency: transitive
    description:
      name: shared_preferences_ios
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.9"
  shared_preferences_linux:
    dependency: transitive
    description:
      name: shared_preferences_linux
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.4"
  shared_preferences_macos:
    dependency: transitive
    description:
      name: shared_preferences_macos
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.2"
  shared_preferences_platform_interface:
    dependency: transitive
    description:
      name: shared_preferences_platform_interface
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.0"
  shared_preferences_web:
    dependency: transitive
    description:
      name: shared_preferences_web
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.3"
  shared_preferences_windows:
    dependency: transitive
    description:
      name: shared_preferences_windows
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.4"
  sky_engine:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.99"
  source_span:
    dependency: transitive
    description:
      name: source_span
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.8.1"
  sqflite:
    dependency: "direct dev"
    description:
      name: sqflite
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.2"
  sqflite_common:
    dependency: transitive
    description:
      name: sqflite_common
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.1+1"
  stack_trace:
    dependency: transitive
    description:
      name: stack_trace
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.10.0"
  stream_channel:
    dependency: transitive
    description:
      name: stream_channel
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.0"
  string_scanner:
    dependency: transitive
    description:
      name: string_scanner
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.1.0"
  synchronized:
    dependency: transitive
    description:
      name: synchronized
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "3.0.0"
  term_glyph:
    dependency: transitive
    description:
      name: term_glyph
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.2.0"
  test_api:
    dependency: transitive
    description:
      name: test_api
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.4.2"
  transformer_page_view:
    dependency: transitive
    description:
      name: transformer_page_view
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.1.6"
  typed_data:
    dependency: transitive
    description:
      name: typed_data
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.3.0"
  url_launcher:
    dependency: "direct dev"
    description:
      name: url_launcher
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "6.0.18"
  url_launcher_android:
    dependency: transitive
    description:
      name: url_launcher_android
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "6.0.14"
  url_launcher_ios:
    dependency: transitive
    description:
      name: url_launcher_ios
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "6.0.14"
  url_launcher_linux:
    dependency: transitive
    description:
      name: url_launcher_linux
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.3"
  url_launcher_macos:
    dependency: transitive
    description:
      name: url_launcher_macos
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.2"
  url_launcher_platform_interface:
    dependency: transitive
    description:
      name: url_launcher_platform_interface
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.5"
  url_launcher_web:
    dependency: transitive
    description:
      name: url_launcher_web
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.6"
  url_launcher_windows:
    dependency: transitive
    description:
      name: url_launcher_windows
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.0.2"
  vector_math:
    dependency: transitive
    description:
      name: vector_math
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.1.0"
  webview_flutter:
    dependency: "direct dev"
    description:
      name: webview_flutter
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.8.0"
  webview_flutter_android:
    dependency: transitive
    description:
      name: webview_flutter_android
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.8.2"
  webview_flutter_platform_interface:
    dependency: transitive
    description:
      name: webview_flutter_platform_interface
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "1.8.1"
  webview_flutter_wkwebview:
    dependency: transitive
    description:
      name: webview_flutter_wkwebview
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.7.1"
  win32:
    dependency: transitive
    description:
      name: win32
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "2.3.6"
  xdg_directories:
    dependency: transitive
    description:
      name: xdg_directories
      url: "https://pub.flutter-io.cn"
    source: hosted
    version: "0.2.0"
sdks:
  dart: ">=2.14.0 <3.0.0"
  flutter: ">=2.5.0"
src/main/resources/code/flutter/pubspec.yaml
New file
@@ -0,0 +1,152 @@
name: hanju
description: A new Flutter project.
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# 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: 1.0.0+1
environment:
  sdk: ">=2.12.0 <3.0.0"
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
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.2
dev_dependencies:
  flutter_test:
    sdk: flutter
  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^1.0.0
  cupertino_icons: ^1.0.3
  permission_handler: ^8.2.6
  shared_preferences: ^2.0.8
  sqflite: ^2.0.0+3
  dio: ^4.0.0
  #轮播图插件
  flutter_swiper: ^1.1.6
  fluttertoast: ^8.0.8
  webview_flutter: ^2.8.0
  #穿山甲广告
  flutter_unionad: ^1.1.9
  #广点通广告
  flutter_tencentad: ^1.1.0
  flutter_widget_from_html_core: ^0.8.3
  #时间日期选择
  flutter_datetime_picker: ^1.5.1
  #二维码生成
  qr_flutter: ^4.0.0
  #分享组件
  share_plus: ^3.0.4
  path_provider: ^2.0.6
  #微信登录
  fluwx_no_pay: ^3.6.1+5
  event_bus: ^2.0.0
  #极光推送
  jpush_flutter: ^2.1.8
  #获取设备信息
  device_info: ^2.0.3
  #加密
  crypto: ^3.0.1
  flutter_spinkit: ^5.1.0
  #下拉刷新
  pull_to_refresh: ^2.0.0
  url_launcher: ^6.0.17
  package_info: ^2.0.2
  launch_review: ^3.0.1
  date_format: ^2.0.4
  #截图插件
  screenshot: ^1.2.3
# 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
  assets:
    - assets/imgs/
  # To add assets to your application, add an assets section, like this:
  # assets:
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg
  # 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
src/main/resources/code/flutter/web/favicon.png
src/main/resources/code/flutter/web/icons/Icon-192.png
src/main/resources/code/flutter/web/icons/Icon-512.png
src/main/resources/code/flutter/web/icons/Icon-maskable-192.png
src/main/resources/code/flutter/web/icons/Icon-maskable-512.png
src/main/resources/code/flutter/web/index.html
New file
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html>
<head>
  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.
    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.
    For more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
    This is a placeholder for base href that will be replaced by the value of
    the `--base-href` argument provided to `flutter build`.
  -->
  <base href="$FLUTTER_BASE_HREF">
  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">
  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="hanju">
  <link rel="apple-touch-icon" href="icons/Icon-192.png">
  <title>hanju</title>
  <link rel="manifest" href="manifest.json">
</head>
<body>
  <!-- This script installs service_worker.js to provide PWA functionality to
       application. For more information, see:
       https://developers.google.com/web/fundamentals/primers/service-workers -->
  <script>
    var serviceWorkerVersion = null;
    var scriptLoaded = false;
    function loadMainDartJs() {
      if (scriptLoaded) {
        return;
      }
      scriptLoaded = true;
      var scriptTag = document.createElement('script');
      scriptTag.src = 'main.dart.js';
      scriptTag.type = 'application/javascript';
      document.body.append(scriptTag);
    }
    if ('serviceWorker' in navigator) {
      // Service workers are supported. Use them.
      window.addEventListener('load', function () {
        // Wait for registration to finish before dropping the <script> tag.
        // Otherwise, the browser will load the script multiple times,
        // potentially different versions.
        var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
        navigator.serviceWorker.register(serviceWorkerUrl)
          .then((reg) => {
            function waitForActivation(serviceWorker) {
              serviceWorker.addEventListener('statechange', () => {
                if (serviceWorker.state == 'activated') {
                  console.log('Installed new service worker.');
                  loadMainDartJs();
                }
              });
            }
            if (!reg.active && (reg.installing || reg.waiting)) {
              // No active web worker and we have installed or are installing
              // one for the first time. Simply wait for it to activate.
              waitForActivation(reg.installing || reg.waiting);
            } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
              // When the app updates the serviceWorkerVersion changes, so we
              // need to ask the service worker to update.
              console.log('New service worker available.');
              reg.update();
              waitForActivation(reg.installing);
            } else {
              // Existing service worker is still good.
              console.log('Loading app from service worker.');
              loadMainDartJs();
            }
          });
        // If service worker doesn't succeed in a reasonable amount of time,
        // fallback to plaint <script> tag.
        setTimeout(() => {
          if (!scriptLoaded) {
            console.warn(
              'Failed to load app from service worker. Falling back to plain <script> tag.',
            );
            loadMainDartJs();
          }
        }, 4000);
      });
    } else {
      // Service workers not supported. Just drop the <script> tag.
      loadMainDartJs();
    }
  </script>
</body>
</html>
src/main/resources/code/flutter/web/manifest.json
New file
@@ -0,0 +1,35 @@
{
    "name": "hanju",
    "short_name": "hanju",
    "start_url": ".",
    "display": "standalone",
    "background_color": "#0175C2",
    "theme_color": "#0175C2",
    "description": "A new Flutter project.",
    "orientation": "portrait-primary",
    "prefer_related_applications": false,
    "icons": [
        {
            "src": "icons/Icon-192.png",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "icons/Icon-512.png",
            "sizes": "512x512",
            "type": "image/png"
        },
        {
            "src": "icons/Icon-maskable-192.png",
            "sizes": "192x192",
            "type": "image/png",
            "purpose": "maskable"
        },
        {
            "src": "icons/Icon-maskable-512.png",
            "sizes": "512x512",
            "type": "image/png",
            "purpose": "maskable"
        }
    ]
}