From d8ef9a783b9e0b2a495f02fdf3daaf27ef49e99d Mon Sep 17 00:00:00 2001
From: admin <weikou2014>
Date: 星期四, 20 一月 2022 18:46:50 +0800
Subject: [PATCH] flutter模板

---
 src/main/resources/code/flutter/lib/ui/common/browser.dart                                                                         |  134 +
 src/main/resources/code/android/library-common/build/intermediates/compile_symbol_list/debug/R.txt                                 |   45 
 src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings                                   |    8 
 src/main/resources/code/flutter/web/icons/Icon-maskable-192.png                                                                    |    0 
 src/main/resources/code/android/app/src/main/java/com/demo/app/utils/browser/MyJavaInterface.java                                  |   37 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png                                |    0 
 src/main/resources/code/flutter/android/app/src/main/res/drawable/launch_background.xml                                            |   12 
 src/main/resources/code/flutter/web/icons/Icon-512.png                                                                             |    0 
 src/main/resources/code/flutter/android/app/src/main/kotlin/com/example/hanju/MainActivity.kt                                      |    6 
 src/main/resources/code/flutter/lib/ui/mine/login.dart                                                                             |  495 +++
 src/main/resources/code/flutter/lib/utils/event_bus_util.dart                                                                      |   10 
 src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/transformed/classes/classes.dex  |    0 
 src/main/resources/code/android/library-common/build/intermediates/runtime_library_classes_jar/debug/classes.jar                   |    0 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json                                        |  122 
 src/main/resources/code/flutter/ios/Runner/Base.lproj/LaunchScreen.storyboard                                                      |   37 
 src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png                                            |    0 
 src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata                                  |    7 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png                                |    0 
 src/main/resources/code/flutter/lib/ui/mine/advice_submit.dart                                                                     |  199 +
 src/main/resources/code/flutter/lib/utils/permission_util.dart                                                                     |  150 +
 src/main/resources/code/flutter/android/app/build.gradle                                                                           |   68 
 src/main/resources/code/flutter/android/build.gradle                                                                               |   29 
 src/main/resources/code/flutter/lib/ui/mine/advice.dart                                                                            |  147 +
 src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist                                       |    8 
 src/main/resources/code/flutter/web/icons/Icon-192.png                                                                             |    0 
 src/main/resources/code/flutter/README.md                                                                                          |   16 
 src/main/resources/code/flutter/web/index.html                                                                                     |  101 
 src/main/resources/code/flutter/lib/utils/pageutils.dart                                                                           |   95 
 src/main/resources/code/android/library-common/build/intermediates/compile_library_classes_jar/debug/classes.jar                   |    0 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png                                |    0 
 src/main/resources/code/flutter/lib/utils/cache_util.dart                                                                          |   57 
 src/main/resources/code/flutter/pubspec.yaml                                                                                       |  152 +
 src/main/resources/code/flutter/android/gradle/wrapper/gradle-wrapper.properties                                                   |    6 
 src/main/resources/code/flutter/android/app/src/main/res/values/styles.xml                                                         |   18 
 src/main/resources/code/flutter/lib/utils/setting_util.dart                                                                        |   46 
 src/main/resources/code/flutter/ios/Flutter/Debug.xcconfig                                                                         |    1 
 src/main/resources/code/flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png                                               |    0 
 src/main/resources/code/android/library-common/build/intermediates/compile_r_class_jar/debug/R.jar                                 |    0 
 src/main/resources/code/flutter/lib/model/common/http_model.dart                                                                   |   16 
 src/main/resources/code/android/library-common/build/intermediates/javac/debug/classes/com/demo/lib/common/widget/FlowLayout.class |    0 
 src/main/resources/code/flutter/lib/ui/widget/base_ui.dart                                                                         |   25 
 src/main/resources/code/flutter/lib/utils/push_util.dart                                                                           |   89 
 src/main/resources/code/flutter/analysis_options.yaml                                                                              |   29 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png                                |    0 
 src/main/resources/code/android/library-common/build/tmp/compileDebugJavaWithJavac/source-classes-mapping.txt                      |  112 
 src/main/resources/code/flutter/lib/utils/ui_constant.dart                                                                         |   40 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png                                |    0 
 src/main/resources/code/flutter/lib/utils/jsinterface.dart                                                                         |  239 +
 src/main/resources/code/flutter/lib/ui/main/mine.dart                                                                              |  539 ++++
 src/main/resources/code/flutter/lib/utils/user_util.dart                                                                           |  109 
 src/main/resources/code/flutter/ios/Runner/Info.plist                                                                              |   45 
 src/main/resources/code/flutter/lib/utils/share_utils.dart                                                                         |   40 
 src/main/resources/code/flutter/web/manifest.json                                                                                  |   35 
 src/main/resources/code/flutter/lib/utils/config_util.dart                                                                         |   55 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png                            |    0 
 src/main/resources/code/flutter/lib/utils/string_util.dart                                                                         |   13 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png                                |    0 
 src/main/resources/code/flutter/lib/ui/widget/dialog.dart                                                                          |  559 ++++
 src/main/resources/code/flutter/android/app/src/profile/AndroidManifest.xml                                                        |    7 
 src/main/resources/code/flutter/lib/utils/app_util.dart                                                                            |   77 
 src/main/resources/code/flutter/lib/utils/ui_utils.dart                                                                            |   28 
 src/main/resources/code/flutter/lib/ui/widget/button.dart                                                                          |  134 +
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md                                          |    5 
 src/main/resources/code/flutter/lib/ui/widget/nav.dart                                                                             |  104 
 src/main/resources/code/android/app/src/main/java/com/demo/app/utils/Constant.java                                                 |    2 
 src/main/resources/code/flutter/ios/Runner/Base.lproj/Main.storyboard                                                              |   26 
 src/main/resources/code/flutter/ios/Flutter/AppFrameworkInfo.plist                                                                 |   26 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png                                |    0 
 src/main/resources/code/flutter/lib/model/common/adinfo_model.dart                                                                 |   29 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png                                 |    0 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png                                |    0 
 src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/results.bin                      |    1 
 src/main/resources/code/flutter/.gitignore                                                                                         |   46 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png                                |    0 
 src/main/resources/code/flutter/lib/ui/widget/sos_ui.dart                                                                          |  105 
 src/main/resources/code/flutter/.metadata                                                                                          |   10 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png                                |    0 
 src/main/resources/code/flutter/lib/ui/main/main.dart                                                                              |  321 ++
 src/main/resources/code/flutter/ios/Runner/AppDelegate.swift                                                                       |   13 
 src/main/resources/code/flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png                                              |    0 
 src/main/resources/code/flutter/lib/main.dart                                                                                      |  219 +
 src/main/resources/code/flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme                                        |   91 
 src/main/resources/code/flutter/ios/Runner.xcodeproj/project.pbxproj                                                               |  484 +++
 src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist                     |    8 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png                            |    0 
 src/main/resources/code/flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png                                               |    0 
 src/main/resources/code/flutter/android/app/src/main/AndroidManifest.xml                                                           |   41 
 src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png                                             |    0 
 src/main/resources/code/flutter/lib/ui/widget/capture.dart                                                                         |   47 
 src/main/resources/code/flutter/pubspec.lock                                                                                       |  691 +++++
 src/main/resources/code/flutter/ios/.gitignore                                                                                     |   34 
 src/main/resources/code/flutter/android/app/src/debug/AndroidManifest.xml                                                          |    7 
 src/main/resources/code/flutter/web/favicon.png                                                                                    |    0 
 src/main/resources/code/flutter/lib/utils/global.dart                                                                              |   28 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png                                |    0 
 src/main/resources/code/flutter/android/settings.gradle                                                                            |   11 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json                                      |   23 
 src/main/resources/code/flutter/android/app/src/main/res/values-night/styles.xml                                                   |   18 
 src/main/resources/code/flutter/ios/Runner.xcworkspace/contents.xcworkspacedata                                                    |    7 
 src/main/resources/code/flutter/ios/Runner/Runner-Bridging-Header.h                                                                |    1 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png                                |    0 
 src/main/resources/code/flutter/android/gradle.properties                                                                          |    3 
 src/main/resources/code/flutter/ios/Flutter/Release.xcconfig                                                                       |    1 
 src/main/resources/code/flutter/android/.gitignore                                                                                 |   13 
 src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings                 |    8 
 src/main/resources/code/flutter/lib/ui/mine/settings.dart                                                                          |  339 ++
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png                                |    0 
 src/main/resources/code/flutter/lib/model/user/user_info.dart                                                                      |   44 
 src/main/resources/code/flutter/lib/utils/ad_util.dart                                                                             |  610 ++++
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png                                 |    0 
 src/main/resources/code/flutter/lib/api/http.dart                                                                                  |  269 ++
 src/main/resources/code/flutter/android/app/src/main/res/drawable-v21/launch_background.xml                                        |   12 
 src/main/resources/code/android/library-common/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt         |   38 
 src/main/resources/code/flutter/lib/utils/encrypt_util.dart                                                                        |    8 
 src/main/resources/code/flutter/web/icons/Icon-maskable-512.png                                                                    |    0 
 src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png                                    |    0 
 116 files changed, 7,883 insertions(+), 57 deletions(-)

diff --git a/src/main/resources/code/android/app/src/main/java/com/demo/app/utils/Constant.java b/src/main/resources/code/android/app/src/main/java/com/demo/app/utils/Constant.java
index d3a51d6..a2d2a2a 100644
--- a/src/main/resources/code/android/app/src/main/java/com/demo/app/utils/Constant.java
+++ b/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";
diff --git a/src/main/resources/code/android/app/src/main/java/com/demo/app/utils/browser/MyJavaInterface.java b/src/main/resources/code/android/app/src/main/java/com/demo/app/utils/browser/MyJavaInterface.java
index c26e6f0..cbe43f4 100644
--- a/src/main/resources/code/android/app/src/main/java/com/demo/app/utils/browser/MyJavaInterface.java
+++ b/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 {
diff --git a/src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/results.bin b/src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/results.bin
new file mode 100644
index 0000000..0d259dd
--- /dev/null
+++ b/src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/results.bin
@@ -0,0 +1 @@
+o/classes
diff --git a/src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/transformed/classes/classes.dex b/src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/transformed/classes/classes.dex
new file mode 100644
index 0000000..d846a26
--- /dev/null
+++ b/src/main/resources/code/android/library-common/build/.transforms/5acd788cb06af19b0e4df3266f878524/transformed/classes/classes.dex
Binary files differ
diff --git a/src/main/resources/code/android/library-common/build/intermediates/compile_library_classes_jar/debug/classes.jar b/src/main/resources/code/android/library-common/build/intermediates/compile_library_classes_jar/debug/classes.jar
index ec676b4..af13d0b 100644
--- a/src/main/resources/code/android/library-common/build/intermediates/compile_library_classes_jar/debug/classes.jar
+++ b/src/main/resources/code/android/library-common/build/intermediates/compile_library_classes_jar/debug/classes.jar
Binary files differ
diff --git a/src/main/resources/code/android/library-common/build/intermediates/compile_r_class_jar/debug/R.jar b/src/main/resources/code/android/library-common/build/intermediates/compile_r_class_jar/debug/R.jar
index e744d33..558aac1 100644
--- a/src/main/resources/code/android/library-common/build/intermediates/compile_r_class_jar/debug/R.jar
+++ b/src/main/resources/code/android/library-common/build/intermediates/compile_r_class_jar/debug/R.jar
Binary files differ
diff --git a/src/main/resources/code/android/library-common/build/intermediates/compile_symbol_list/debug/R.txt b/src/main/resources/code/android/library-common/build/intermediates/compile_symbol_list/debug/R.txt
index d75fdd8..7707a2e 100644
--- a/src/main/resources/code/android/library-common/build/intermediates/compile_symbol_list/debug/R.txt
+++ b/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 }
diff --git a/src/main/resources/code/android/library-common/build/intermediates/javac/debug/classes/com/demo/lib/common/widget/FlowLayout.class b/src/main/resources/code/android/library-common/build/intermediates/javac/debug/classes/com/demo/lib/common/widget/FlowLayout.class
new file mode 100644
index 0000000..cc708a5
--- /dev/null
+++ b/src/main/resources/code/android/library-common/build/intermediates/javac/debug/classes/com/demo/lib/common/widget/FlowLayout.class
Binary files differ
diff --git a/src/main/resources/code/android/library-common/build/intermediates/runtime_library_classes_jar/debug/classes.jar b/src/main/resources/code/android/library-common/build/intermediates/runtime_library_classes_jar/debug/classes.jar
index fef51a7..f7b2c84 100644
--- a/src/main/resources/code/android/library-common/build/intermediates/runtime_library_classes_jar/debug/classes.jar
+++ b/src/main/resources/code/android/library-common/build/intermediates/runtime_library_classes_jar/debug/classes.jar
Binary files differ
diff --git a/src/main/resources/code/android/library-common/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt b/src/main/resources/code/android/library-common/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt
index 5ffb71f..cd318ed 100644
--- a/src/main/resources/code/android/library-common/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt
+++ b/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
diff --git a/src/main/resources/code/android/library-common/build/tmp/compileDebugJavaWithJavac/source-classes-mapping.txt b/src/main/resources/code/android/library-common/build/tmp/compileDebugJavaWithJavac/source-classes-mapping.txt
index 479ac9a..3a4bcd4 100644
--- a/src/main/resources/code/android/library-common/build/tmp/compileDebugJavaWithJavac/source-classes-mapping.txt
+++ b/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
diff --git a/src/main/resources/code/flutter/.gitignore b/src/main/resources/code/flutter/.gitignore
new file mode 100644
index 0000000..0fa6b67
--- /dev/null
+++ b/src/main/resources/code/flutter/.gitignore
@@ -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
diff --git a/src/main/resources/code/flutter/.metadata b/src/main/resources/code/flutter/.metadata
new file mode 100644
index 0000000..a5584fc
--- /dev/null
+++ b/src/main/resources/code/flutter/.metadata
@@ -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
diff --git a/src/main/resources/code/flutter/README.md b/src/main/resources/code/flutter/README.md
new file mode 100644
index 0000000..7889c54
--- /dev/null
+++ b/src/main/resources/code/flutter/README.md
@@ -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.
diff --git a/src/main/resources/code/flutter/analysis_options.yaml b/src/main/resources/code/flutter/analysis_options.yaml
new file mode 100644
index 0000000..61b6c4d
--- /dev/null
+++ b/src/main/resources/code/flutter/analysis_options.yaml
@@ -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
diff --git a/src/main/resources/code/flutter/android/.gitignore b/src/main/resources/code/flutter/android/.gitignore
new file mode 100644
index 0000000..6f56801
--- /dev/null
+++ b/src/main/resources/code/flutter/android/.gitignore
@@ -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
diff --git a/src/main/resources/code/flutter/android/app/build.gradle b/src/main/resources/code/flutter/android/app/build.gradle
new file mode 100644
index 0000000..8fa81ac
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/build.gradle
@@ -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"
+}
diff --git a/src/main/resources/code/flutter/android/app/src/debug/AndroidManifest.xml b/src/main/resources/code/flutter/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..39b60bd
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/debug/AndroidManifest.xml
@@ -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>
diff --git a/src/main/resources/code/flutter/android/app/src/main/AndroidManifest.xml b/src/main/resources/code/flutter/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5fd94a1
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/AndroidManifest.xml
@@ -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>
diff --git a/src/main/resources/code/flutter/android/app/src/main/kotlin/com/example/hanju/MainActivity.kt b/src/main/resources/code/flutter/android/app/src/main/kotlin/com/example/hanju/MainActivity.kt
new file mode 100644
index 0000000..e2a769d
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/kotlin/com/example/hanju/MainActivity.kt
@@ -0,0 +1,6 @@
+package com.example.hanju
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/drawable-v21/launch_background.xml b/src/main/resources/code/flutter/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -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>
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/drawable/launch_background.xml b/src/main/resources/code/flutter/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/drawable/launch_background.xml
@@ -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>
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/values-night/styles.xml b/src/main/resources/code/flutter/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..449a9f9
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/values-night/styles.xml
@@ -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>
diff --git a/src/main/resources/code/flutter/android/app/src/main/res/values/styles.xml b/src/main/resources/code/flutter/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..d74aa35
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/main/res/values/styles.xml
@@ -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>
diff --git a/src/main/resources/code/flutter/android/app/src/profile/AndroidManifest.xml b/src/main/resources/code/flutter/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..39b60bd
--- /dev/null
+++ b/src/main/resources/code/flutter/android/app/src/profile/AndroidManifest.xml
@@ -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>
diff --git a/src/main/resources/code/flutter/android/build.gradle b/src/main/resources/code/flutter/android/build.gradle
new file mode 100644
index 0000000..ed45c65
--- /dev/null
+++ b/src/main/resources/code/flutter/android/build.gradle
@@ -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
+}
diff --git a/src/main/resources/code/flutter/android/gradle.properties b/src/main/resources/code/flutter/android/gradle.properties
new file mode 100644
index 0000000..94adc3a
--- /dev/null
+++ b/src/main/resources/code/flutter/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/src/main/resources/code/flutter/android/gradle/wrapper/gradle-wrapper.properties b/src/main/resources/code/flutter/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..bc6a58a
--- /dev/null
+++ b/src/main/resources/code/flutter/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Jun 23 08:50:38 CEST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
diff --git a/src/main/resources/code/flutter/android/settings.gradle b/src/main/resources/code/flutter/android/settings.gradle
new file mode 100644
index 0000000..44e62bc
--- /dev/null
+++ b/src/main/resources/code/flutter/android/settings.gradle
@@ -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"
diff --git a/src/main/resources/code/flutter/ios/.gitignore b/src/main/resources/code/flutter/ios/.gitignore
new file mode 100644
index 0000000..7a7f987
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/.gitignore
@@ -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
diff --git a/src/main/resources/code/flutter/ios/Flutter/AppFrameworkInfo.plist b/src/main/resources/code/flutter/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000..8d4492f
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Flutter/AppFrameworkInfo.plist
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Flutter/Debug.xcconfig b/src/main/resources/code/flutter/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000..592ceee
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Flutter/Debug.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/src/main/resources/code/flutter/ios/Flutter/Release.xcconfig b/src/main/resources/code/flutter/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..592ceee
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Flutter/Release.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.pbxproj b/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..51d5d90
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.pbxproj
@@ -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 */;
+}
diff --git a/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:">
+   </FileRef>
+</Workspace>
diff --git a/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/main/resources/code/flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000..a28140c
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Runner.xcworkspace/contents.xcworkspacedata b/src/main/resources/code/flutter/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..1d526a1
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:Runner.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Runner/AppDelegate.swift b/src/main/resources/code/flutter/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000..70693e4
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/AppDelegate.swift
@@ -0,0 +1,13 @@
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+  override func application(
+    _ application: UIApplication,
+    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+  ) -> Bool {
+    GeneratedPluginRegistrant.register(with: self)
+    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+  }
+}
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d36b1fa
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+  "images" : [
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-83.5x83.5@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "1024x1024",
+      "idiom" : "ios-marketing",
+      "filename" : "Icon-App-1024x1024@1x.png",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000..dc9ada4
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000..28c6bf0
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000..2ccbfd9
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000..f091b6b
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000..4cde121
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000..d0ef06e
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000..dcdc230
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000..2ccbfd9
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000..c8f9ed8
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000..a6d6b86
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000..a6d6b86
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000..75b2d16
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000..c4df70d
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000..6a84f41
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000..d0e1f58
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000..0bedcf2
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
Binary files differ
diff --git a/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000..89c2725
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/src/main/resources/code/flutter/ios/Runner/Base.lproj/LaunchScreen.storyboard b/src/main/resources/code/flutter/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..f2e259c
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Runner/Base.lproj/Main.storyboard b/src/main/resources/code/flutter/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Base.lproj/Main.storyboard
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Runner/Info.plist b/src/main/resources/code/flutter/ios/Runner/Info.plist
new file mode 100644
index 0000000..a0ea543
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Info.plist
@@ -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>
diff --git a/src/main/resources/code/flutter/ios/Runner/Runner-Bridging-Header.h b/src/main/resources/code/flutter/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000..308a2a5
--- /dev/null
+++ b/src/main/resources/code/flutter/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/src/main/resources/code/flutter/lib/api/http.dart b/src/main/resources/code/flutter/lib/api/http.dart
new file mode 100644
index 0000000..beb274b
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/api/http.dart
@@ -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 {
+  ///鏌ラ槄鍚戞垜姹傛晳鐨凷OS
+  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 {
+  ///鏌ラ槄鍚戞垜姹傛晳鐨凷OS
+  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;
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/main.dart b/src/main/resources/code/flutter/lib/main.dart
new file mode 100644
index 0000000..3ac3564
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/main.dart
@@ -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>锛屾偍鍚屾剰骞舵帴鍙楁墍鏈夋潯娆惧悗锛屾墠鑳戒娇鐢ㄦ垜浠蒋浠躲�傝嫢鎮ㄦ敞鍐屾垚涓烘湰杞欢浼氬憳鎴栨帴鍙楀ソ鍙嬬殑閭�璇峰嵆琛ㄦ槑鎮ㄥ厑璁稿悜鏈蒋浠朵腑鐨勫ソ鍙嬫彁渚涙偍鐨勫湴鐞嗕綅缃拰杞ㄨ抗绛変俊鎭�備负纭繚杞欢姝e父杩愯鎴戜滑闇�瑕佽幏寰楋紝灏ゅ叾鏄細<br>" +
+            "1銆佹垜浠鎮ㄧ殑涓汉淇℃伅锛堝寘鎷絾涓嶉檺浜�<b style='color:red'>璁惧MAC鍦板潃銆両MEI/Android ID銆佷綅缃俊鎭�</b>绛変俊鎭級鐨勬敹闆�/淇濆瓨/浣跨敤/瀵瑰鎻愪緵/淇濇姢绛夎鍒欐潯娆�,浠ュ強鎮ㄧ殑鐢ㄦ埛鏉冨埄绛夋潯娆撅紱<br>" +
+            "2銆佺害瀹氭垜浠殑闄愬埗璐d换銆佸厤璐f潯娆撅紱<br>" +
+            "3銆佸叾浠栦互鍔犵矖鎴栨枩浣撳瓧杩涜鏍囪瘑鐨勯噸瑕佹潯娆俱��<br>" +
+            "4銆佺壒鍒敵鏄庯細鏈蒋浠跺畾浣嶅畧鎶ょ瓑鍔熻兘闇�鍙屾柟閮戒笅杞芥湰杞欢骞跺悓鎰忔巿鏉冨悗鎵嶅彲姝e父浣跨敤锛屼笉娑夊強渚电姱涓汉闅愮闂銆傝幏鍙栧湴鐞嗕俊鎭繀椤诲湪鐢ㄦ埛鍙屾柟鐭ユ儏骞跺悓鎰忕殑鎯呭喌涓嬭繘琛岋紝鏈蒋浠朵粎闄愮敤浜庡搴�/浜插弸/鐔熶汉/鏈嬪弸闂翠娇鐢ㄣ��<br>" +
+            "濡傛偍瀵瑰崗璁湁浠讳綍鐤戣檻锛屽彲閫氳繃鐢靛瓙閭锛歞w365@foxmail.com 鍚戞垜浠闂紝鎴戜滑灏嗕负鎮ㄧ璇氳В绛斻�傛偍鐐瑰嚮鈥滃悓鎰忓苟缁х画鈥濈殑琛屼负浠h〃鎮ㄥ凡闃呰瀹屾瘯骞舵帴鍙椾互涓婂崗璁叏閮ㄦ潯娆俱�傚鎮ㄥ悓鎰忎互涓婂崗璁唴瀹癸紝璇锋偍鐐瑰嚮鈥滃悓鎰忓苟缁х画鈥濓紝寮�濮嬩娇鐢ㄦ湰杞欢銆�";
+
+        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),
+                      ),
+                    ],
+                  ),
+                )
+              ],
+            )));
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/model/common/adinfo_model.dart b/src/main/resources/code/flutter/lib/model/common/adinfo_model.dart
new file mode 100644
index 0000000..fdb195f
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/model/common/adinfo_model.dart
@@ -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;
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/code/flutter/lib/model/common/http_model.dart b/src/main/resources/code/flutter/lib/model/common/http_model.dart
new file mode 100644
index 0000000..3f57498
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/model/common/http_model.dart
@@ -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});
+}
diff --git a/src/main/resources/code/flutter/lib/model/user/user_info.dart b/src/main/resources/code/flutter/lib/model/user/user_info.dart
new file mode 100644
index 0000000..ab4182c
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/model/user/user_info.dart
@@ -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;
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/common/browser.dart b/src/main/resources/code/flutter/lib/ui/common/browser.dart
new file mode 100644
index 0000000..e39da93
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/common/browser.dart
@@ -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;
+                      }
+                    });
+                  },
+                ))
+              ],
+            )));
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/main/main.dart b/src/main/resources/code/flutter/lib/ui/main/main.dart
new file mode 100644
index 0000000..b9ae03a
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/main/main.dart
@@ -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),
+              )
+            ],
+          ),
+        ));
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/main/mine.dart b/src/main/resources/code/flutter/lib/ui/main/mine.dart
new file mode 100644
index 0000000..00073b4
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/main/mine.dart
@@ -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;
+}
diff --git a/src/main/resources/code/flutter/lib/ui/mine/advice.dart b/src/main/resources/code/flutter/lib/ui/mine/advice.dart
new file mode 100644
index 0000000..7c1857c
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/mine/advice.dart
@@ -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,
+            )
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/mine/advice_submit.dart b/src/main/resources/code/flutter/lib/ui/mine/advice_submit.dart
new file mode 100644
index 0000000..c74a9a2
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/mine/advice_submit.dart
@@ -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;
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/mine/login.dart b/src/main/resources/code/flutter/lib/ui/mine/login.dart
new file mode 100644
index 0000000..7cca134
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/mine/login.dart
@@ -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),
+              )
+            ],
+          )),
+    );
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/mine/settings.dart b/src/main/resources/code/flutter/lib/ui/mine/settings.dart
new file mode 100644
index 0000000..9bae546
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/mine/settings.dart
@@ -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: "绗笁鏂筍DK鍒楄〃",
+            //     content: "",
+            //     onClick: () {
+            //
+            //       ConfigUtil.getConfig(ConfigKey.sdkList).then((value) {
+            //         if (!StringUtil.isNullOrEmpty(value)) {
+            //           NavigatorUtil.navigateToNextPage(
+            //               context, BrowserPage(title: "绗笁鏂筍DK鍒楄〃", 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,
+                    )))
+          ])),
+    );
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/widget/base_ui.dart b/src/main/resources/code/flutter/lib/ui/widget/base_ui.dart
new file mode 100644
index 0000000..2f7d34a
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/widget/base_ui.dart
@@ -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),
+    );
+  },
+);
diff --git a/src/main/resources/code/flutter/lib/ui/widget/button.dart b/src/main/resources/code/flutter/lib/ui/widget/button.dart
new file mode 100644
index 0000000..78159de
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/widget/button.dart
@@ -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,
+                  ),
+          )),
+    );
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/widget/capture.dart b/src/main/resources/code/flutter/lib/ui/widget/capture.dart
new file mode 100644
index 0000000..943f9b5
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/widget/capture.dart
@@ -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';
+
+///瀵箇idget鎴浘
+
+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 "";
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/widget/dialog.dart b/src/main/resources/code/flutter/lib/ui/widget/dialog.dart
new file mode 100644
index 0000000..a9d776c
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/widget/dialog.dart
@@ -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,
+                        ))
+                  ],
+                ))));
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/widget/nav.dart b/src/main/resources/code/flutter/lib/ui/widget/nav.dart
new file mode 100644
index 0000000..ac59fb3
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/widget/nav.dart
@@ -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,
+                ))
+          ],
+        ),
+      )
+    ]);
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/ui/widget/sos_ui.dart b/src/main/resources/code/flutter/lib/ui/widget/sos_ui.dart
new file mode 100644
index 0000000..0b9a24f
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/ui/widget/sos_ui.dart
@@ -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;
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/ad_util.dart b/src/main/resources/code/flutter/lib/utils/ad_util.dart
new file mode 100644
index 0000000..9c0335a
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/ad_util.dart
@@ -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鍙互鑾峰彇锛宖alse绂佹鑾峰彇銆傞粯璁や负true
+      //     lat: 1.0,
+      //     //褰搃sCanUseLocation=false鏃讹紝鍙紶鍏ュ湴鐞嗕綅缃俊鎭紝绌垮北鐢瞫dk浣跨敤鎮ㄤ紶鍏ョ殑鍦扮悊浣嶇疆淇℃伅lat
+      //     lon: 1.0,
+      //     //褰搃sCanUseLocation=false鏃讹紝鍙紶鍏ュ湴鐞嗕綅缃俊鎭紝绌垮北鐢瞫dk浣跨敤鎮ㄤ紶鍏ョ殑鍦扮悊浣嶇疆淇℃伅lon
+      //     isCanUsePhoneState: false,
+      //     //鏄惁鍏佽SDK涓诲姩浣跨敤鎵嬫満纭欢鍙傛暟锛屽锛歩mei
+      //     imei: "123",
+      //     //褰搃sCanUsePhoneState=false鏃讹紝鍙紶鍏mei淇℃伅锛岀┛灞辩敳sdk浣跨敤鎮ㄤ紶鍏ョ殑imei淇℃伅
+      //     isCanUseWifiState: false,
+      //     //鏄惁鍏佽SDK涓诲姩浣跨敤ACCESS_WIFI_STATE鏉冮檺
+      //     isCanUseWriteExternal: false,
+      //     //鏄惁鍏佽SDK涓诲姩浣跨敤WRITE_EXTERNAL_STORAGE鏉冮檺
+      //     oaid: "111", //寮�鍙戣�呭彲浠ヤ紶鍏aid
+      //   );
+      // }
+
+      await FlutterUnionad.register(
+          androidAppId: csjAppId,
+          //绌垮北鐢插箍鍛� Android appid 蹇呭~
+          iosAppId: "",
+          //绌垮北鐢插箍鍛� ios appid 蹇呭~
+          useTextureView: false,
+          //浣跨敤TextureView鎺т欢鎾斁瑙嗛,榛樿涓篠urfaceView,褰撴湁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 寮�灞忓箍鍛婂箍鍛奿d 蹇呭~
+      androidCodeId: pid,
+      //ios 寮�灞忓箍鍛婂箍鍛奿d 蹇呭~
+      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 淇℃伅娴佸箍鍛奿d 蹇呭~
+      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 婵�鍔辫棰戝箍鍛奿d  蹇呭~
+      iosCodeId: "",
+      //ios 婵�鍔辫棰戝箍鍛奿d  蹇呭~
+      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";
+}
diff --git a/src/main/resources/code/flutter/lib/utils/app_util.dart b/src/main/resources/code/flutter/lib/utils/app_util.dart
new file mode 100644
index 0000000..cbfd303
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/app_util.dart
@@ -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);
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/cache_util.dart b/src/main/resources/code/flutter/lib/utils/cache_util.dart
new file mode 100644
index 0000000..7b3bcba
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/cache_util.dart
@@ -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();
+    }
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/config_util.dart b/src/main/resources/code/flutter/lib/utils/config_util.dart
new file mode 100644
index 0000000..6887d8f
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/config_util.dart
@@ -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 }
diff --git a/src/main/resources/code/flutter/lib/utils/encrypt_util.dart b/src/main/resources/code/flutter/lib/utils/encrypt_util.dart
new file mode 100644
index 0000000..ceefd70
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/encrypt_util.dart
@@ -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();
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/event_bus_util.dart b/src/main/resources/code/flutter/lib/utils/event_bus_util.dart
new file mode 100644
index 0000000..cd4c691
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/event_bus_util.dart
@@ -0,0 +1,10 @@
+import 'package:event_bus/event_bus.dart';
+EventBus eventBus = EventBus();
+
+
+
+class LoginEventBus {
+  final bool isLogin;
+  LoginEventBus(this.isLogin);
+}
+
diff --git a/src/main/resources/code/flutter/lib/utils/global.dart b/src/main/resources/code/flutter/lib/utils/global.dart
new file mode 100644
index 0000000..34aea0f
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/global.dart
@@ -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;
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/jsinterface.dart b/src/main/resources/code/flutter/lib/utils/jsinterface.dart
new file mode 100644
index 0000000..966ed27
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/jsinterface.dart
@@ -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;
+          }
+        }
+      });
+    });
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/pageutils.dart b/src/main/resources/code/flutter/lib/utils/pageutils.dart
new file mode 100644
index 0000000..f7e97b4
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/pageutils.dart
@@ -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;
+}
diff --git a/src/main/resources/code/flutter/lib/utils/permission_util.dart b/src/main/resources/code/flutter/lib/utils/permission_util.dart
new file mode 100644
index 0000000..6c65858
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/permission_util.dart
@@ -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;
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/push_util.dart b/src/main/resources/code/flutter/lib/utils/push_util.dart
new file mode 100644
index 0000000..9be77b5
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/push_util.dart
@@ -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);
+    });
+
+    //濡傛灉鐧诲綍浜嗗氨璁剧疆鐢ㄦ埛鐨剈id
+    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();
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/setting_util.dart b/src/main/resources/code/flutter/lib/utils/setting_util.dart
new file mode 100644
index 0000000..cf0b872
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/setting_util.dart
@@ -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;
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/share_utils.dart b/src/main/resources/code/flutter/lib/utils/share_utils.dart
new file mode 100644
index 0000000..5ec3dc2
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/share_utils.dart
@@ -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]);
+    }
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/string_util.dart b/src/main/resources/code/flutter/lib/utils/string_util.dart
new file mode 100644
index 0000000..a40a7a7
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/string_util.dart
@@ -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;
+  }
+
+}
diff --git a/src/main/resources/code/flutter/lib/utils/ui_constant.dart b/src/main/resources/code/flutter/lib/utils/ui_constant.dart
new file mode 100644
index 0000000..2b5016f
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/ui_constant.dart
@@ -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";
+
+
+}
diff --git a/src/main/resources/code/flutter/lib/utils/ui_utils.dart b/src/main/resources/code/flutter/lib/utils/ui_utils.dart
new file mode 100644
index 0000000..9726cb0
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/ui_utils.dart
@@ -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;
+  }
+}
diff --git a/src/main/resources/code/flutter/lib/utils/user_util.dart b/src/main/resources/code/flutter/lib/utils/user_util.dart
new file mode 100644
index 0000000..8e3f031
--- /dev/null
+++ b/src/main/resources/code/flutter/lib/utils/user_util.dart
@@ -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");
+  }
+}
diff --git a/src/main/resources/code/flutter/pubspec.lock b/src/main/resources/code/flutter/pubspec.lock
new file mode 100644
index 0000000..df6225e
--- /dev/null
+++ b/src/main/resources/code/flutter/pubspec.lock
@@ -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"
diff --git a/src/main/resources/code/flutter/pubspec.yaml b/src/main/resources/code/flutter/pubspec.yaml
new file mode 100644
index 0000000..bdffb91
--- /dev/null
+++ b/src/main/resources/code/flutter/pubspec.yaml
@@ -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
diff --git a/src/main/resources/code/flutter/web/favicon.png b/src/main/resources/code/flutter/web/favicon.png
new file mode 100644
index 0000000..8aaa46a
--- /dev/null
+++ b/src/main/resources/code/flutter/web/favicon.png
Binary files differ
diff --git a/src/main/resources/code/flutter/web/icons/Icon-192.png b/src/main/resources/code/flutter/web/icons/Icon-192.png
new file mode 100644
index 0000000..b749bfe
--- /dev/null
+++ b/src/main/resources/code/flutter/web/icons/Icon-192.png
Binary files differ
diff --git a/src/main/resources/code/flutter/web/icons/Icon-512.png b/src/main/resources/code/flutter/web/icons/Icon-512.png
new file mode 100644
index 0000000..88cfd48
--- /dev/null
+++ b/src/main/resources/code/flutter/web/icons/Icon-512.png
Binary files differ
diff --git a/src/main/resources/code/flutter/web/icons/Icon-maskable-192.png b/src/main/resources/code/flutter/web/icons/Icon-maskable-192.png
new file mode 100644
index 0000000..eb9b4d7
--- /dev/null
+++ b/src/main/resources/code/flutter/web/icons/Icon-maskable-192.png
Binary files differ
diff --git a/src/main/resources/code/flutter/web/icons/Icon-maskable-512.png b/src/main/resources/code/flutter/web/icons/Icon-maskable-512.png
new file mode 100644
index 0000000..d69c566
--- /dev/null
+++ b/src/main/resources/code/flutter/web/icons/Icon-maskable-512.png
Binary files differ
diff --git a/src/main/resources/code/flutter/web/index.html b/src/main/resources/code/flutter/web/index.html
new file mode 100644
index 0000000..1bdf475
--- /dev/null
+++ b/src/main/resources/code/flutter/web/index.html
@@ -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>
diff --git a/src/main/resources/code/flutter/web/manifest.json b/src/main/resources/code/flutter/web/manifest.json
new file mode 100644
index 0000000..5547d57
--- /dev/null
+++ b/src/main/resources/code/flutter/web/manifest.json
@@ -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"
+        }
+    ]
+}

--
Gitblit v1.8.0