├── .flutter-plugins-dependencies ├── .fvm └── fvm_config.json ├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── README_CH.md ├── _config.yml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── air │ │ │ │ └── flutter_app_sample │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── key.jks ├── key.properties ├── key_README.txt └── settings.gradle ├── assets ├── Butterfly-209.mp4 ├── avatar.jpg ├── bumble_bee_captions.srt ├── child3.svg ├── child6.svg ├── child7.svg ├── child8.svg ├── circle.svg ├── dino2.svg ├── egypt1.svg ├── flutter-mark-square-64.png ├── head1.svg ├── login_top_gif.gif ├── pexels-photo-396547.jpg ├── place_view_page_banner_0.jpeg ├── place_view_page_banner_1.jpeg └── place_view_page_banner_2.jpeg ├── doc ├── README_CH_v1.0.md ├── README_CH_v2.0.md ├── README_Solution_To_The_Problem.md ├── README_v1.0.md └── README_v2.0.md ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── ChineseCupertinoLocalizations.dart ├── common │ ├── Read │ ├── config │ │ ├── ApiConfig.dart │ │ ├── EnvironmentConfig.dart │ │ ├── PageNameConfig.dart │ │ └── StringConfig.dart │ ├── helper │ │ ├── tip_helper.dart │ │ └── tip_type.dart │ └── util │ │ ├── LogUtil.dart │ │ └── StringUtil.dart ├── component │ ├── BasePresenter.dart │ ├── BaseSource.dart │ ├── BaseView.dart │ ├── Read │ ├── barcode │ │ ├── app_barcode_scanner_widget.dart │ │ ├── barcode_main_page.dart │ │ ├── creator_page.dart │ │ ├── custom_size_scanner_page.dart │ │ ├── full_screen_scanner_page.dart │ │ ├── select_scanner_style_page.dart │ │ └── task_next_page.dart │ ├── builder │ │ ├── future_builder_async_request_page.dart │ │ ├── future_builder_main_page.dart │ │ ├── stream_builder_async_request_page.dart │ │ └── stream_builder_main_page.dart │ ├── component_config.dart │ ├── filter │ │ └── select_color_filter_page.dart │ ├── fit │ │ └── fitted_box_page.dart │ ├── game │ │ ├── MainGamePage.dart │ │ └── WeatherPage.dart │ ├── image │ │ └── image_picker_page.dart │ ├── login │ │ ├── login_contract.dart │ │ ├── login_page.dart │ │ └── tv_login_page.dart │ ├── main │ │ ├── main_config.dart │ │ ├── main_list_item_widget.dart │ │ ├── main_page.dart │ │ ├── main_view_model.dart │ │ └── tv_main_page.dart │ ├── message │ │ ├── awesome_message_main_page.dart │ │ ├── message_popup_route.dart │ │ ├── popup_page.dart │ │ └── tool_page.dart │ ├── network │ │ └── network_check_page.dart │ ├── paint │ │ └── sun_main_page.dart │ ├── personal │ │ ├── personal_config.dart │ │ ├── personal_drawer_widget.dart │ │ ├── personal_face_widget.dart │ │ ├── personal_slide_drawer.dart │ │ └── user_info_page.dart │ ├── route │ │ ├── launch_page.dart │ │ ├── second_page.dart │ │ └── third_page.dart │ ├── search │ │ └── SearchPage.dart │ ├── setting │ │ └── setting_page.dart │ ├── shop │ │ ├── Product.dart │ │ ├── ShoppingList.dart │ │ └── ShoppingListItem.dart │ ├── state │ │ ├── FrogColor.dart │ │ ├── inherited_widget_child.dart │ │ ├── inherited_widget_main_page.dart │ │ ├── user_info.dart │ │ └── user_inherited_widget.dart │ ├── tab │ │ ├── navigation_drawer_page.dart │ │ ├── navigation_rail_page.dart │ │ └── tab_main_page.dart │ ├── test │ │ └── TestPage.dart │ └── video │ │ └── video_player_page.dart ├── data │ ├── Read │ ├── request │ │ └── LoginRequestBean.dart │ └── response │ │ └── User.dart ├── di │ └── Read ├── entrance_global_config.dart ├── generated_plugin_registrant.dart ├── global_view_model.dart ├── main.dart ├── net │ └── HttpContext.dart ├── sample │ ├── CollapsingToolbarPage.dart │ ├── DrawerVariouslyPage.dart │ ├── MainSortListPage.dart │ ├── ViewPagerFragmentPage.dart │ ├── anim │ │ ├── AnimOfSwitchPage.dart │ │ ├── AnimatedBuilderPage.dart │ │ ├── AnimatedContainerPage.dart │ │ ├── AppPageRoute.dart │ │ ├── ColorTweenPage.dart │ │ ├── FadeInImagePage.dart │ │ ├── HeroAnimPage.dart │ │ ├── MainAnimSortPage.dart │ │ ├── OpacityAndAnimatedOpacityPage.dart │ │ ├── TransformPage.dart │ │ ├── draw_anim_page.dart │ │ ├── icon │ │ │ └── main_icon_anim_page.dart │ │ └── snappable_page.dart │ ├── chart │ │ ├── bar_chart │ │ │ ├── bar_chart_page.dart │ │ │ ├── bar_chart_page2.dart │ │ │ └── samples │ │ │ │ ├── bar_chart_sample1.dart │ │ │ │ ├── bar_chart_sample2.dart │ │ │ │ ├── bar_chart_sample3.dart │ │ │ │ ├── bar_chart_sample4.dart │ │ │ │ └── bar_chart_sample5.dart │ │ ├── chart_page.dart │ │ ├── line_chart │ │ │ ├── line_chart_page.dart │ │ │ ├── line_chart_page2.dart │ │ │ ├── line_chart_page3.dart │ │ │ ├── line_chart_page4.dart │ │ │ └── samples │ │ │ │ ├── line_chart_sample1.dart │ │ │ │ ├── line_chart_sample2.dart │ │ │ │ ├── line_chart_sample3.dart │ │ │ │ ├── line_chart_sample4.dart │ │ │ │ ├── line_chart_sample5.dart │ │ │ │ ├── line_chart_sample6.dart │ │ │ │ ├── line_chart_sample7.dart │ │ │ │ └── line_chart_sample8.dart │ │ ├── pie_chart │ │ │ ├── pie_chart_page.dart │ │ │ └── samples │ │ │ │ ├── indicator.dart │ │ │ │ ├── pie_chart_sample1.dart │ │ │ │ └── pie_chart_sample2.dart │ │ └── scatter_chart │ │ │ ├── samples │ │ │ ├── scatter_chart_sample1.dart │ │ │ └── scatter_chart_sample2.dart │ │ │ └── scatter_chart_page.dart │ ├── clip │ │ └── clip_main_page.dart │ ├── drag │ │ └── DragListPage.dart │ ├── file │ │ └── FileMainPage.dart │ ├── image │ │ └── main_image_sort_page.dart │ ├── ink │ │ └── ink_page.dart │ ├── loading │ │ ├── loading_modal_popup_route.dart │ │ └── main_loading_page.dart │ ├── navigation │ │ └── curved_navigation_bar_page.dart │ ├── notifier │ │ ├── CardInfoPage.dart │ │ ├── CardMainPage.dart │ │ ├── CardModel.dart │ │ └── CardModelByNotifierProvider.dart │ ├── overlay │ │ ├── main_overlay_page.dart │ │ └── simple_overlay_page.dart │ ├── picker │ │ └── main_picker_page.dart │ ├── popup │ │ └── main_popup_page.dart │ ├── progress │ │ └── main_progress_page.dart │ ├── segment │ │ ├── drop_down_page.dart │ │ └── segment_page.dart │ ├── text │ │ ├── RichTextPage.dart │ │ └── input_text_page.dart │ ├── tip │ │ └── flushbar_page.dart │ ├── wave │ │ ├── main_wave_page.dart │ │ ├── wave_arc_clipper.dart │ │ ├── wave_oval_clipper.dart │ │ └── wave_triangle_clipper.dart │ ├── webview │ │ ├── air_license_page.dart │ │ └── flutter_web_page.dart │ └── wheel │ │ └── list_wheel_scroll_view_page.dart ├── tv │ ├── app_raw_key_board_listener_widget.dart │ └── key_code.dart └── ui │ ├── Read │ ├── common │ ├── AppCommonListItem.dart │ ├── AppCommonTextField.dart │ └── AppCommonToolBar.dart │ ├── route │ └── AppRoute.dart │ └── style │ └── AppStyle.dart ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── app_icon_1024.png │ │ ├── app_icon_128.png │ │ ├── app_icon_16.png │ │ ├── app_icon_256.png │ │ ├── app_icon_32.png │ │ ├── app_icon_512.png │ │ └── app_icon_64.png │ ├── Base.lproj │ └── MainMenu.xib │ ├── Configs │ ├── AppInfo.xcconfig │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart ├── web ├── avatar.jpg ├── favicon.png ├── icons │ ├── Icon-192.png │ └── Icon-512.png ├── index.html ├── js │ └── jsQR.js └── manifest.json └── windows ├── .gitignore ├── CMakeLists.txt ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake └── runner ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── resources └── app_icon.ico ├── run_loop.cpp ├── run_loop.h ├── runner.exe.manifest ├── utils.cpp ├── utils.h ├── win32_window.cpp └── win32_window.h /.fvm/fvm_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "flutterSdkVersion": "3.0.3", 3 | "flavors": {} 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | .fvm/flutter_sdk 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | .dart_tool/ 27 | .flutter-plugins 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Generated.xcconfig 62 | **/ios/Flutter/app.flx 63 | **/ios/Flutter/app.zip 64 | **/ios/Flutter/flutter_assets/ 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: b712a172f9694745f50505c93340883493b505e5 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 33 30 | ndkVersion flutter.ndkVersion 31 | 32 | compileOptions { 33 | sourceCompatibility JavaVersion.VERSION_1_8 34 | targetCompatibility JavaVersion.VERSION_1_8 35 | } 36 | 37 | kotlinOptions { 38 | jvmTarget = '1.8' 39 | } 40 | 41 | sourceSets { 42 | main.java.srcDirs += 'src/main/kotlin' 43 | } 44 | 45 | defaultConfig { 46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 47 | applicationId "com.air.flutter_app_sample" 48 | // You can update the following values to match your application needs. 49 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. 50 | minSdkVersion 19 51 | targetSdkVersion flutter.targetSdkVersion 52 | versionCode flutterVersionCode.toInteger() 53 | versionName flutterVersionName 54 | multiDexEnabled true 55 | } 56 | 57 | buildTypes { 58 | release { 59 | // TODO: Add your own signing config for the release build. 60 | // Signing with the debug keys for now, so `flutter run --release` works. 61 | signingConfig signingConfigs.debug 62 | } 63 | } 64 | } 65 | 66 | flutter { 67 | source '../..' 68 | } 69 | 70 | dependencies { 71 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 72 | implementation "androidx.multidex:multidex:2.0.1" 73 | } 74 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 9 | 17 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/air/flutter_app_sample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.air.flutter_app_sample 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.1.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 7 | -------------------------------------------------------------------------------- /android/key.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/android/key.jks -------------------------------------------------------------------------------- /android/key.properties: -------------------------------------------------------------------------------- 1 | storePassword=123456 2 | keyPassword=123456 3 | keyAlias=key 4 | storeFile=/Users/air/develop_work/flutter/personal_project/flutter_app_sample/android/key.jks -------------------------------------------------------------------------------- /android/key_README.txt: -------------------------------------------------------------------------------- 1 | storePassword=123456 2 | keyPassword=123456 -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /assets/Butterfly-209.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/assets/Butterfly-209.mp4 -------------------------------------------------------------------------------- /assets/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/assets/avatar.jpg -------------------------------------------------------------------------------- /assets/bumble_bee_captions.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,200 --> 00:00:01,750 3 | [ Birds chirping ] 4 | 5 | 2 6 | 00:00:02,300 --> 00:00:05,000 7 | [ Buzzing ] 8 | -------------------------------------------------------------------------------- /assets/circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | -------------------------------------------------------------------------------- /assets/flutter-mark-square-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/assets/flutter-mark-square-64.png -------------------------------------------------------------------------------- /assets/login_top_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/assets/login_top_gif.gif -------------------------------------------------------------------------------- /assets/pexels-photo-396547.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/assets/pexels-photo-396547.jpg -------------------------------------------------------------------------------- /assets/place_view_page_banner_0.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/assets/place_view_page_banner_0.jpeg -------------------------------------------------------------------------------- /assets/place_view_page_banner_1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/assets/place_view_page_banner_1.jpeg -------------------------------------------------------------------------------- /assets/place_view_page_banner_2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/assets/place_view_page_banner_2.jpeg -------------------------------------------------------------------------------- /doc/README_Solution_To_The_Problem.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Flutter app sample 3 | 4 | img: /images/flutter_logo.jpg 5 | summary: Flutter项目示例 6 | categories: app sample 7 | top: true 8 | tags: 9 | - Flutter 10 | - Dart 11 | - MVP 12 | - Dio 13 | - DesignPatterns 14 | 15 | 16 | --- 17 | 18 | ---- 19 | 20 | ![totem](https://github.com/pdliuw/pdliuw.github.io/blob/master/images/totem_four_logo.jpg?raw=true) 21 | 22 | 23 | 问题1、Flutter更新依赖的库的版本后,但是在项目中获取的一直是旧版本的! 24 | 25 | ``` 26 | 27 | * 1、打开窗口:打开“Terminal” 或“终端”窗口 28 | * 2、执行命令: 29 | * 2.1、"flutter packages get" 命令 30 | * 2.2、"flutter packages upgrade" 命令 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ai_barcode (0.0.1): 3 | - Flutter 4 | - MTBBarcodeScanner 5 | - connectivity (0.0.1): 6 | - Flutter 7 | - Reachability 8 | - Flutter (1.0.0) 9 | - image_picker (0.0.1): 10 | - Flutter 11 | - MTBBarcodeScanner (5.0.11) 12 | - "permission_handler (5.1.0+2)": 13 | - Flutter 14 | - Reachability (3.2) 15 | - shared_preferences (0.0.1): 16 | - Flutter 17 | - url_launcher (0.0.1): 18 | - Flutter 19 | - video_player (0.0.1): 20 | - Flutter 21 | - webview_flutter (0.0.1): 22 | - Flutter 23 | 24 | DEPENDENCIES: 25 | - ai_barcode (from `.symlinks/plugins/ai_barcode/ios`) 26 | - connectivity (from `.symlinks/plugins/connectivity/ios`) 27 | - Flutter (from `Flutter`) 28 | - image_picker (from `.symlinks/plugins/image_picker/ios`) 29 | - permission_handler (from `.symlinks/plugins/permission_handler/ios`) 30 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 31 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`) 32 | - video_player (from `.symlinks/plugins/video_player/ios`) 33 | - webview_flutter (from `.symlinks/plugins/webview_flutter/ios`) 34 | 35 | SPEC REPOS: 36 | trunk: 37 | - MTBBarcodeScanner 38 | - Reachability 39 | 40 | EXTERNAL SOURCES: 41 | ai_barcode: 42 | :path: ".symlinks/plugins/ai_barcode/ios" 43 | connectivity: 44 | :path: ".symlinks/plugins/connectivity/ios" 45 | Flutter: 46 | :path: Flutter 47 | image_picker: 48 | :path: ".symlinks/plugins/image_picker/ios" 49 | permission_handler: 50 | :path: ".symlinks/plugins/permission_handler/ios" 51 | shared_preferences: 52 | :path: ".symlinks/plugins/shared_preferences/ios" 53 | url_launcher: 54 | :path: ".symlinks/plugins/url_launcher/ios" 55 | video_player: 56 | :path: ".symlinks/plugins/video_player/ios" 57 | webview_flutter: 58 | :path: ".symlinks/plugins/webview_flutter/ios" 59 | 60 | SPEC CHECKSUMS: 61 | ai_barcode: 67fb0a7b732dbb87e92b59bb90a438db9383fa2f 62 | connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 63 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c 64 | image_picker: 50e7c7ff960e5f58faa4d1f4af84a771c671bc4a 65 | MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb 66 | permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0 67 | Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 68 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d 69 | url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef 70 | video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e 71 | webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b 72 | 73 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 74 | 75 | COCOAPODS: 1.10.1 76 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | 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. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_app_sample 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | NSAppTransportSecurity 45 | 46 | NSAllowsArbitraryLoads 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/common/Read: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/lib/common/Read -------------------------------------------------------------------------------- /lib/common/config/ApiConfig.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_app_sample/common/config/EnvironmentConfig.dart'; 2 | 3 | ///Api config class! 4 | /// 5 | /// 6 | class ApiConfig { 7 | static const String RELEASE_URL = "http://101.201.77.210"; 8 | static const String TEST_URL = "http://101.201.77.210"; 9 | static const String DEBUG_URL = "http://101.201.77.210"; 10 | static String BASE_URL = getUrl(); 11 | static const int CONNECT_TIME_OUT = 5000; 12 | static const int RECEIVE_TIME_OUT = 3000; 13 | 14 | static String getUrl() { 15 | if (EnvironmentConfig.DEBUG_URL) { 16 | return TEST_URL; 17 | } else { 18 | return RELEASE_URL; 19 | } 20 | } 21 | ///URL path! 22 | static const String GET_VERIFICATION_CODE_URL = "/api/app/v1/LoginCtrl/getVerificationCode"; 23 | static const String LOGIN_URL = "/api/app/v1/LoginCtrl/login"; 24 | } 25 | -------------------------------------------------------------------------------- /lib/common/config/EnvironmentConfig.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | class EnvironmentConfig{ 4 | 5 | static bool DEBUG_URL = true; 6 | static bool DEBUG_TOAST = true; 7 | } -------------------------------------------------------------------------------- /lib/common/config/PageNameConfig.dart: -------------------------------------------------------------------------------- 1 | 2 | class PageNameConfig{ 3 | 4 | final String mLoginPageName = "登陆"; 5 | final String mShoppingListPageName = "商品列表"; 6 | } -------------------------------------------------------------------------------- /lib/common/config/StringConfig.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_app_sample/common/config/PageNameConfig.dart'; 2 | 3 | class StringConfig{ 4 | 5 | 6 | static final PageNameConfig _pageNameConfig = PageNameConfig(); 7 | 8 | ///Get PageNameConfig object! 9 | static PageNameConfig get pageNameConfig{ 10 | return _pageNameConfig; 11 | } 12 | } -------------------------------------------------------------------------------- /lib/common/helper/tip_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:ai_awesome_message/ai_awesome_message.dart' as awesome_message; 2 | import 'package:airoute/airoute.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'tip_type.dart' as tip_type; 6 | 7 | /// 8 | /// TipHelper 9 | class TipHelper { 10 | /// 11 | /// showTip 12 | /// [context] 13 | /// [title] 14 | /// [message] 15 | /// [tipType] 16 | static showTip({ 17 | required BuildContext context, 18 | String? title, 19 | String message = '', 20 | tip_type.TipType tipType = tip_type.TipType.INFO, 21 | }) { 22 | awesome_message.TipType awesomeTipType; 23 | if (tipType == tip_type.TipType.INFO) { 24 | awesomeTipType = awesome_message.TipType.INFO; 25 | } else if (tipType == tip_type.TipType.WARN) { 26 | awesomeTipType = awesome_message.TipType.WARN; 27 | } else if (tipType == tip_type.TipType.ERROR) { 28 | awesomeTipType = awesome_message.TipType.ERROR; 29 | } else if (tipType == tip_type.TipType.COMPLETE) { 30 | awesomeTipType = awesome_message.TipType.COMPLETE; 31 | } else { 32 | awesomeTipType = awesome_message.TipType.INFO; 33 | } 34 | Airoute.push( 35 | route: awesome_message.AwesomeMessageRoute( 36 | theme: null, 37 | settings: RouteSettings(name: "/ai_awesome_message"), 38 | awesomeMessage: awesome_message.AwesomeHelper.createAwesome( 39 | title: "${title ?? "提示"}", 40 | message: "${message}", 41 | tipType: awesomeTipType, 42 | ), 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/common/helper/tip_type.dart: -------------------------------------------------------------------------------- 1 | enum TipType { 2 | INFO, 3 | WARN, 4 | ERROR, 5 | COMPLETE, 6 | } 7 | -------------------------------------------------------------------------------- /lib/common/util/LogUtil.dart: -------------------------------------------------------------------------------- 1 | class LogUtil { 2 | static final StringBuffer stringBuffer = new StringBuffer(); 3 | 4 | static void log(Object object) { 5 | print("${object}"); 6 | } 7 | 8 | static void logWithTag({String? tag, Object? message}) { 9 | print("${createLine()}"); 10 | 11 | String all = "TAG:$tag, $message"; 12 | print("$all"); 13 | 14 | print("${createLine()}"); 15 | } 16 | 17 | static String createSpace({int value = 0}) { 18 | stringBuffer.clear(); 19 | 20 | for (int i = 0; i < value; i++) { 21 | stringBuffer.write(" "); 22 | } 23 | return stringBuffer.toString(); 24 | } 25 | 26 | static String createLine({int max = 100}) { 27 | stringBuffer.clear(); 28 | 29 | for (int i = 0; i < max; i++) { 30 | stringBuffer.write("-"); 31 | } 32 | 33 | return stringBuffer.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/common/util/StringUtil.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class StringUtil { 4 | static String get getEmpty => emptyString; 5 | static String emptyString = ""; 6 | 7 | ///是否是空数据 8 | static bool isEmpty(Object object) { 9 | if (object == null) { 10 | return true; 11 | } 12 | if (object is String) { 13 | if (object.length == 0) { 14 | return true; 15 | } else { 16 | return false; 17 | } 18 | } 19 | 20 | return false; 21 | } 22 | 23 | ///是否是空对象 24 | static bool isNull(Object object) { 25 | if (object == null) { 26 | return true; 27 | } else { 28 | return false; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/component/BasePresenter.dart: -------------------------------------------------------------------------------- 1 | ///MVP-Presenter- 2 | abstract class BasePresenter { 3 | create(); 4 | destroy(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/component/BaseSource.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | abstract class BaseSource{ 4 | 5 | } -------------------------------------------------------------------------------- /lib/component/BaseView.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_app_sample/component/BasePresenter.dart'; 2 | 3 | ///MVP--View- 4 | abstract class BaseView { 5 | setPresenter(T presenter); 6 | } 7 | -------------------------------------------------------------------------------- /lib/component/Read: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/lib/component/Read -------------------------------------------------------------------------------- /lib/component/barcode/barcode_main_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:airoute/airoute.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_app_sample/component/barcode/select_scanner_style_page.dart'; 5 | 6 | import 'creator_page.dart'; 7 | 8 | /// 9 | /// BarcodeMainPage 10 | class BarcodeMainPage extends StatefulWidget { 11 | @override 12 | _BarcodeMainPageState createState() => _BarcodeMainPageState(); 13 | } 14 | 15 | class _BarcodeMainPageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: Text("条码"), 21 | ), 22 | body: Column( 23 | crossAxisAlignment: CrossAxisAlignment.center, 24 | mainAxisAlignment: MainAxisAlignment.center, 25 | children: [ 26 | Expanded( 27 | child: AppCardOutlinedStyleWidget.defaultStyle( 28 | onTap: () { 29 | //跳转页面=扫描二维码 30 | Airoute.push(route: MaterialPageRoute(builder: (context) { 31 | return SelectScannerStylePage(); 32 | })); 33 | }, 34 | child: Center( 35 | child: AppCardElevatedStyleWidget.defaultStyle( 36 | child: ListTile( 37 | title: Text("Scan 1D barcode/QR code"), 38 | ), 39 | ), 40 | ), 41 | ), 42 | ), 43 | Expanded( 44 | child: AppCardOutlinedStyleWidget.defaultStyle( 45 | onTap: () { 46 | //跳转页面=生成二维码 47 | Airoute.push(route: MaterialPageRoute(builder: (context) { 48 | return CreatorPage(); 49 | })); 50 | }, 51 | child: Center( 52 | child: AppCardElevatedStyleWidget.defaultStyle( 53 | child: ListTile( 54 | title: Text("Create QR code"), 55 | ), 56 | ), 57 | ), 58 | ), 59 | ), 60 | ], 61 | ), 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/component/barcode/custom_size_scanner_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import 'app_barcode_scanner_widget.dart'; 5 | 6 | /// 7 | /// CustomSizeScannerPage 8 | class CustomSizeScannerPage extends StatefulWidget { 9 | @override 10 | _CustomSizeScannerPageState createState() => _CustomSizeScannerPageState(); 11 | } 12 | 13 | class _CustomSizeScannerPageState extends State { 14 | String _code = ''; 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar(), 19 | body: Column( 20 | children: [ 21 | Row( 22 | mainAxisAlignment: MainAxisAlignment.center, 23 | children: [ 24 | Text(_code), 25 | ], 26 | ), 27 | Expanded( 28 | child: AppBarcodeScannerWidget.defaultStyle( 29 | resultCallback: (String code) { 30 | setState(() { 31 | _code = code; 32 | }); 33 | }, 34 | ), 35 | ), 36 | ], 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/component/barcode/full_screen_scanner_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'app_barcode_scanner_widget.dart'; 4 | 5 | /// 6 | /// FullScreenScannerPage 7 | class FullScreenScannerPage extends StatefulWidget { 8 | @override 9 | _FullScreenScannerPageState createState() => _FullScreenScannerPageState(); 10 | } 11 | 12 | class _FullScreenScannerPageState extends State { 13 | String _code = ''; 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | appBar: AppBar(), 18 | body: Column( 19 | children: [ 20 | Row( 21 | mainAxisAlignment: MainAxisAlignment.center, 22 | children: [ 23 | Text("「$_code」"), 24 | ], 25 | ), 26 | Expanded( 27 | child: AppBarcodeScannerWidget.defaultStyle( 28 | resultCallback: (String code) { 29 | setState(() { 30 | _code = code; 31 | }); 32 | }, 33 | ), 34 | ), 35 | ], 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/component/barcode/select_scanner_style_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:airoute/airoute.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_app_sample/component/barcode/full_screen_scanner_page.dart'; 5 | 6 | import 'custom_size_scanner_page.dart'; 7 | 8 | /// 9 | /// SelectScannerStylePage 10 | class SelectScannerStylePage extends StatefulWidget { 11 | @override 12 | State createState() { 13 | return _SelectScannerStyleState(); 14 | } 15 | } 16 | 17 | /// 18 | /// _SelectScannerStyleState 19 | class _SelectScannerStyleState extends State { 20 | @override 21 | Widget build(BuildContext context) { 22 | return Scaffold( 23 | appBar: AppBar( 24 | title: Text("Select Scanner Style"), 25 | ), 26 | body: Column( 27 | children: [ 28 | Spacer(), 29 | AppCardOutlinedStyleWidget.defaultStyle( 30 | onTap: () { 31 | Airoute.push(route: MaterialPageRoute(builder: (context) { 32 | return FullScreenScannerPage(); 33 | })); 34 | }, 35 | child: ListTile( 36 | leading: Icon(Icons.fullscreen), 37 | title: Text("FullScreen Style"), 38 | ), 39 | ), 40 | AppCardOutlinedStyleWidget.defaultStyle( 41 | onTap: () { 42 | Airoute.push(route: MaterialPageRoute(builder: (context) { 43 | return CustomSizeScannerPage(); 44 | })); 45 | }, 46 | child: ListTile( 47 | leading: Icon(Icons.color_lens_outlined), 48 | title: Text("CustomSize Style"), 49 | ), 50 | ), 51 | Spacer(), 52 | ], 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/component/barcode/task_next_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:airoute/airoute.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | /// 8 | /// TaskNextPage 9 | class TaskNextPage extends StatefulWidget { 10 | @override 11 | State createState() { 12 | return _TaskNextState(); 13 | } 14 | } 15 | 16 | /// 17 | /// _TaskNextState 18 | class _TaskNextState extends State { 19 | String _boxNumberInputed = ""; 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | double screenWidth = window.physicalSize.width / window.devicePixelRatio; 24 | double screenHeight = window.physicalSize.height / window.devicePixelRatio; 25 | 26 | var screenWidthSize = screenWidth; 27 | return Scaffold( 28 | appBar: AppBar( 29 | title: Text("手输号码"), 30 | ), 31 | body: Column( 32 | crossAxisAlignment: CrossAxisAlignment.center, 33 | children: [ 34 | Center( 35 | child: Container( 36 | width: screenWidthSize / 5 * 4, 37 | child: TextFormField( 38 | initialValue: "", 39 | decoration: InputDecoration( 40 | labelText: '无法扫描的号码', 41 | hintText: "请输入无法扫描的号码", 42 | errorText: "", 43 | helperText: "helper", 44 | border: UnderlineInputBorder( 45 | borderSide: BorderSide(), 46 | ), 47 | ), 48 | textAlign: TextAlign.start, 49 | enabled: true, 50 | onChanged: (String content) { 51 | _boxNumberInputed = content; 52 | }, 53 | ), 54 | ), 55 | ), 56 | MaterialButton( 57 | onPressed: () { 58 | /* 59 | 检查扫码的箱子号码的状态 60 | */ 61 | showCupertinoDialog( 62 | context: context, 63 | builder: (BuildContext context) { 64 | return CupertinoAlertDialog( 65 | content: Text("内容 : $_boxNumberInputed"), 66 | actions: [ 67 | CupertinoDialogAction( 68 | onPressed: () { 69 | Airoute.pop(); 70 | }, 71 | child: Text("知道了"), 72 | ), 73 | ], 74 | ); 75 | }, 76 | ); 77 | }, 78 | color: Theme.of(context).primaryColor, 79 | minWidth: screenWidthSize / 3, 80 | textColor: Colors.white, 81 | child: Tooltip( 82 | message: "", 83 | child: Text("确认"), 84 | ), 85 | ), 86 | ], 87 | ), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/component/builder/future_builder_async_request_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// 5 | /// FutureBuilderAsyncRequestPage 6 | class FutureBuilderAsyncRequestPage extends StatefulWidget { 7 | const FutureBuilderAsyncRequestPage({Key? key}) : super(key: key); 8 | 9 | @override 10 | _FutureBuilderAsyncRequestPageState createState() => _FutureBuilderAsyncRequestPageState(); 11 | } 12 | 13 | class _FutureBuilderAsyncRequestPageState extends State { 14 | final Future _calculation = Future.delayed( 15 | const Duration(seconds: 10), 16 | () => 'Data Loaded', 17 | ); 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | } 23 | 24 | static Future _getNetworkData() async { 25 | // return "努力加载中..."; 26 | return Future.delayed( 27 | const Duration(seconds: 10), 28 | ).whenComplete(() => "{'name': 'James', 'nickName': 'Apple'}"); 29 | // yield "已获取数据,解析中..."; 30 | // await Future.delayed(const Duration(seconds: 10)); 31 | // yield "{'name': 'James', 'nickName': 'Apple'}"; 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Scaffold( 37 | appBar: AppBar( 38 | title: Text("使用FutureBuilder异步操作"), 39 | ), 40 | body: AppCardOutlinedStyleWidget.defaultStyle( 41 | child: Row( 42 | children: [ 43 | Expanded( 44 | child: Column( 45 | mainAxisAlignment: MainAxisAlignment.center, 46 | crossAxisAlignment: CrossAxisAlignment.center, 47 | children: [ 48 | Spacer(), 49 | FlutterLogo(), 50 | AppCardOutlinedStyleWidget.defaultStyle( 51 | child: Text("使用FutureBuilder模拟异步交互"), 52 | ), 53 | Spacer(), 54 | FutureBuilder( 55 | future: _calculation, 56 | builder: (BuildContext context, AsyncSnapshot snapshot) { 57 | return Column( 58 | mainAxisAlignment: MainAxisAlignment.center, 59 | crossAxisAlignment: CrossAxisAlignment.center, 60 | children: [ 61 | if (snapshot.connectionState != ConnectionState.done) CircularProgressIndicator(), 62 | Text("${snapshot.connectionState}"), 63 | Text("${snapshot.data}"), 64 | ], 65 | ); 66 | }), 67 | Spacer(), 68 | Spacer(), 69 | Spacer(), 70 | ], 71 | ), 72 | ), 73 | ], 74 | ), 75 | ), 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/component/builder/future_builder_main_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:airoute/airoute.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | /// 6 | /// FutureBuilderMainPage 7 | class FutureBuilderMainPage extends StatefulWidget { 8 | const FutureBuilderMainPage({Key? key}) : super(key: key); 9 | 10 | @override 11 | _FutureBuilderMainPageState createState() => _FutureBuilderMainPageState(); 12 | } 13 | 14 | class _FutureBuilderMainPageState extends State { 15 | final List _list = [ 16 | { 17 | "title": "使用FutureBuilder异步操作", 18 | "routeName": "/FutureBuilderMainPage/FutureBuilderAsyncRequestPage", 19 | }, 20 | ]; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Scaffold( 25 | appBar: AppBar( 26 | title: Text("FutureBuilder"), 27 | ), 28 | body: ListView.builder( 29 | itemBuilder: (context, index) { 30 | return AppCardOutlinedStyleWidget.defaultStyle( 31 | onTap: () { 32 | Airoute.pushNamed(routeName: "${_list[index]['routeName']}"); 33 | }, 34 | child: Padding( 35 | padding: EdgeInsets.all(16), 36 | child: Column( 37 | children: [Text("${_list[index]['title']}")], 38 | ), 39 | ), 40 | ); 41 | }, 42 | itemCount: _list.length, 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/component/builder/stream_builder_async_request_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// 5 | /// StreamBuilderAsyncRequestPage 6 | class StreamBuilderAsyncRequestPage extends StatefulWidget { 7 | const StreamBuilderAsyncRequestPage({Key? key}) : super(key: key); 8 | 9 | @override 10 | _StreamBuilderAsyncRequestPageState createState() => _StreamBuilderAsyncRequestPageState(); 11 | } 12 | 13 | class _StreamBuilderAsyncRequestPageState extends State { 14 | final Stream _bids = (_getNetworkData)(); 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | } 20 | 21 | static Stream _getNetworkData() async* { 22 | yield "努力加载中..."; 23 | await Future.delayed(const Duration(seconds: 10)); 24 | yield "已获取数据,解析中..."; 25 | await Future.delayed(const Duration(seconds: 10)); 26 | yield "{'name': 'James', 'nickName': 'Apple'}"; 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Scaffold( 32 | appBar: AppBar( 33 | title: Text("使用StreamBuilder异步操作"), 34 | ), 35 | body: AppCardOutlinedStyleWidget.defaultStyle( 36 | child: Row( 37 | children: [ 38 | Expanded( 39 | child: Column( 40 | mainAxisAlignment: MainAxisAlignment.center, 41 | crossAxisAlignment: CrossAxisAlignment.center, 42 | children: [ 43 | Spacer(), 44 | FlutterLogo(), 45 | AppCardOutlinedStyleWidget.defaultStyle( 46 | child: Text("使用StreamBuilder模拟异步交互"), 47 | ), 48 | Spacer(), 49 | StreamBuilder( 50 | stream: _bids, 51 | builder: (BuildContext context, AsyncSnapshot snapshot) { 52 | return Column( 53 | mainAxisAlignment: MainAxisAlignment.center, 54 | crossAxisAlignment: CrossAxisAlignment.center, 55 | children: [ 56 | if (snapshot.connectionState != ConnectionState.done) CircularProgressIndicator(), 57 | Text("${snapshot.connectionState}"), 58 | Text("${snapshot.data}"), 59 | ], 60 | ); 61 | }), 62 | Spacer(), 63 | Spacer(), 64 | Spacer(), 65 | ], 66 | ), 67 | ), 68 | ], 69 | ), 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/component/builder/stream_builder_main_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:airoute/airoute.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | /// 6 | /// StreamBuilderMainPage 7 | class StreamBuilderMainPage extends StatefulWidget { 8 | const StreamBuilderMainPage({Key? key}) : super(key: key); 9 | 10 | @override 11 | _StreamBuilderMainPageState createState() => _StreamBuilderMainPageState(); 12 | } 13 | 14 | class _StreamBuilderMainPageState extends State { 15 | final List _list = [ 16 | { 17 | "title": "使用StreamBuilder异步操作", 18 | "routeName": "/StreamBuilderMainPage/StreamBuilderAsyncRequestPage", 19 | }, 20 | ]; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Scaffold( 25 | appBar: AppBar( 26 | title: Text("StreamBuilder"), 27 | ), 28 | body: ListView.builder( 29 | itemBuilder: (context, index) { 30 | return AppCardOutlinedStyleWidget.defaultStyle( 31 | onTap: () { 32 | Airoute.pushNamed(routeName: "${_list[index]['routeName']}"); 33 | }, 34 | child: Padding( 35 | padding: EdgeInsets.all(16), 36 | child: Column( 37 | children: [Text("${_list[index]['title']}")], 38 | ), 39 | ), 40 | ); 41 | }, 42 | itemCount: _list.length, 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/component/component_config.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// ComponentConfig 3 | class ComponentConfig { 4 | /// 5 | /// [BAR_CODE_REQUEST_PERMISSION]web: false;mobile: true 6 | static const bool BAR_CODE_REQUEST_PERMISSION = false; 7 | } 8 | -------------------------------------------------------------------------------- /lib/component/fit/fitted_box_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// FittedBox 5 | class FittedBoxPage extends StatefulWidget { 6 | const FittedBoxPage({Key? key}) : super(key: key); 7 | 8 | @override 9 | _FittedBoxPageState createState() => _FittedBoxPageState(); 10 | } 11 | 12 | class _FittedBoxPageState extends State with SingleTickerProviderStateMixin { 13 | final List _list = [ 14 | "A", 15 | "B", 16 | "C", 17 | "D", 18 | "E", 19 | "F", 20 | "G", 21 | "H", 22 | "I", 23 | "J", 24 | "K", 25 | "L", 26 | "M", 27 | "N", 28 | "O", 29 | "P", 30 | "Q", 31 | "R", 32 | "S", 33 | "T", 34 | "U", 35 | "V", 36 | "W", 37 | "X", 38 | "Y", 39 | "Z", 40 | ]; 41 | 42 | late AnimationController _animationController; 43 | 44 | @override 45 | void initState() { 46 | super.initState(); 47 | _animationController = AnimationController( 48 | vsync: this, 49 | lowerBound: 1.0, 50 | upperBound: (_list.length + 1).toDouble(), 51 | duration: Duration(seconds: 1 * _list.length), 52 | reverseDuration: Duration(seconds: 1 * _list.length), 53 | ); 54 | _animationController.addStatusListener((status) { 55 | if (status == AnimationStatus.completed) { 56 | _animationController.reset(); 57 | _animationController.forward(); 58 | } 59 | }); 60 | 61 | //post 62 | WidgetsBinding.instance.addPostFrameCallback((timeStamp) { 63 | _animationController.forward(); 64 | }); 65 | } 66 | 67 | @override 68 | void dispose() { 69 | _animationController.stop(); 70 | _animationController.dispose(); 71 | super.dispose(); 72 | } 73 | 74 | @override 75 | Widget build(BuildContext context) { 76 | return Scaffold( 77 | appBar: AppBar( 78 | title: Text("FittedBox"), 79 | ), 80 | body: AnimatedBuilder( 81 | animation: _animationController, 82 | builder: (context, child) { 83 | int length = (_animationController.value).toInt(); 84 | String value = _getValueFromList(length); 85 | 86 | return Flex( 87 | direction: Axis.vertical, 88 | children: [ 89 | Flexible( 90 | child: Container( 91 | width: double.infinity, 92 | height: 200, 93 | color: Theme.of(context).iconTheme.color, 94 | child: FittedBox( 95 | child: Text("$value"), 96 | ), 97 | ), 98 | flex: 1, 99 | ), 100 | Flexible( 101 | child: Center( 102 | child: TextField( 103 | enabled: false, 104 | controller: TextEditingController(text: value), 105 | ), 106 | ), 107 | flex: 1, 108 | ), 109 | ], 110 | ); 111 | }), 112 | ); 113 | } 114 | 115 | String _getValueFromList(int length) { 116 | int subEnd = length++; 117 | List subList = _list.sublist(0, subEnd); 118 | return subList.toString(); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /lib/component/game/MainGamePage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MainGamePage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return _MainGameState(); 7 | } 8 | } 9 | 10 | /// 11 | /// _MainGameState 12 | class _MainGameState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar(), 17 | body: Center( 18 | child: Text("小游戏"), 19 | ), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/component/game/WeatherPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class WeatherPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return _WeatherState(); 7 | } 8 | } 9 | 10 | class _WeatherState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container(); 14 | } 15 | } 16 | 17 | class WeatherPaint extends CustomPainter { 18 | @override 19 | void paint(Canvas canvas, Size size) { 20 | Paint paint = Paint(); 21 | 22 | canvas.drawCircle(Offset(100, 100), 100, paint); 23 | } 24 | 25 | @override 26 | bool shouldRepaint(CustomPainter oldDelegate) { 27 | return true; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/component/image/image_picker_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:air_design/air_design.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:image_picker/image_picker.dart'; 7 | 8 | /// 9 | /// ImagePickerPage 10 | class ImagePickerPage extends StatefulWidget { 11 | @override 12 | _ImagePickerPageState createState() => _ImagePickerPageState(); 13 | } 14 | 15 | class _ImagePickerPageState extends State { 16 | /// 17 | /// ImagePicker 18 | final ImagePicker _picker = ImagePicker(); 19 | 20 | PickedFile? _pickedFile; 21 | 22 | /// 23 | /// pickGallery 24 | void _pickGallery() async { 25 | final pickedFile = await _picker.getImage( 26 | source: ImageSource.gallery, 27 | maxWidth: 200, 28 | maxHeight: 200, 29 | imageQuality: 50, 30 | ); 31 | //ui 32 | setState(() { 33 | _pickedFile = pickedFile; 34 | }); 35 | } 36 | 37 | @override 38 | void initState() { 39 | super.initState(); 40 | } 41 | 42 | @override 43 | void dispose() { 44 | super.dispose(); 45 | } 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | return Scaffold( 50 | appBar: AppBar( 51 | title: Text("image picker"), 52 | ), 53 | body: Column( 54 | children: [ 55 | Expanded( 56 | child: AppCardOutlinedStyleWidget.defaultStyle( 57 | child: InteractiveViewer( 58 | minScale: 0.5, 59 | maxScale: 5.0, 60 | child: _previewWidget(), 61 | ), 62 | )), 63 | ], 64 | ), 65 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, 66 | floatingActionButton: FloatingActionButton( 67 | onPressed: () { 68 | _pickGallery(); 69 | }, 70 | tooltip: "Pick Image from gallery", 71 | child: Icon(Icons.photo_library), 72 | ), 73 | ); 74 | } 75 | 76 | Widget _previewWidget() { 77 | if (_pickedFile == null) { 78 | return Container( 79 | child: Text("please picker one"), 80 | alignment: Alignment.center, 81 | ); 82 | } 83 | if (kIsWeb) { 84 | // Why network? 85 | // See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform 86 | return Image.network(_pickedFile!.path); 87 | } else { 88 | return Semantics(child: Image.file(File(_pickedFile!.path)), label: 'image_picker_example_picked_image'); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/component/main/main_list_item_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:airoute/airoute.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_vector_icons/flutter_vector_icons.dart'; 5 | import 'package:url_launcher/url_launcher.dart'; 6 | 7 | /// 8 | /// MainListItemWidget 9 | class MainListItemWidget extends StatefulWidget { 10 | dynamic itemData; 11 | MainListItemWidget.defaultStyle({ 12 | Key? key, 13 | required this.itemData, 14 | }) : super(key: key) {} 15 | @override 16 | _MainListItemWidgetState createState() => _MainListItemWidgetState(); 17 | } 18 | 19 | class _MainListItemWidgetState extends State { 20 | @override 21 | Widget build(BuildContext context) { 22 | return AppCardOutlinedStyleWidget.defaultStyle( 23 | onTap: () { 24 | Airoute.pushNamedWithAnimation( 25 | routeName: "${widget.itemData['routeName']}", 26 | routePageAnimation: AirouteTransition.Slide, 27 | ); 28 | }, 29 | child: ListTile( 30 | isThreeLine: true, 31 | leading: CircleAvatar( 32 | child: Text("${widget.itemData['title'].substring(0, 1)}"), 33 | ), 34 | title: Text("${widget.itemData['title']}"), 35 | subtitle: Column( 36 | mainAxisAlignment: MainAxisAlignment.start, 37 | crossAxisAlignment: CrossAxisAlignment.start, 38 | children: [ 39 | Text("${widget.itemData['subtitle']}"), 40 | Row( 41 | children: [ 42 | Expanded( 43 | flex: 2, 44 | child: Wrap( 45 | spacing: 8, 46 | runSpacing: 8, 47 | crossAxisAlignment: WrapCrossAlignment.center, 48 | children: [ 49 | // InkWell( 50 | // child: SvgPicture.network( 51 | // "${widget.itemData['link']['version']}", 52 | // ), 53 | // onTap: () { 54 | // launch("${widget.itemData['link']['pub']}"); 55 | // }), 56 | InkWell( 57 | child: Icon( 58 | MaterialCommunityIcons.github, 59 | ), 60 | onTap: () { 61 | launch("${widget.itemData['link']['github']}"); 62 | }) 63 | ], 64 | ), 65 | ), 66 | Expanded( 67 | flex: 1, 68 | child: Wrap( 69 | children: [ 70 | Icon( 71 | MaterialCommunityIcons.copyright, 72 | color: Theme.of(context).primaryColorDark, 73 | ), 74 | AppTextBodyText2Widget.defaultStyle(data: "${widget.itemData['author']['nickname']}"), 75 | ], 76 | ), 77 | ), 78 | ], 79 | ), 80 | ], 81 | ), 82 | ), 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/component/main/main_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// MainViewModel 4 | class MainViewModel extends ChangeNotifier { 5 | static MainViewModel? _instance; 6 | 7 | MainViewModel._(); 8 | 9 | static MainViewModel getInstance() { 10 | if (_instance == null) { 11 | _instance = MainViewModel._(); 12 | } 13 | return _instance!; 14 | } 15 | 16 | void notify() { 17 | notifyListeners(); 18 | } 19 | 20 | static void releaseInstance() { 21 | _instance = null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/component/message/awesome_message_main_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/component/message/popup_page.dart'; 3 | 4 | /// 5 | /// AwesomeMessageMainPage 6 | class AwesomeMessageMainPage extends StatefulWidget { 7 | @override 8 | _AwesomeMessageMainPageState createState() => _AwesomeMessageMainPageState(); 9 | } 10 | 11 | class _AwesomeMessageMainPageState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | body: PopupPage(), 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/component/network/network_check_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:connectivity_plus/connectivity_plus.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/services.dart'; 6 | 7 | /// 8 | /// NetworkCheckPage 9 | class NetworkCheckPage extends StatefulWidget { 10 | @override 11 | _NetworkCheckPageState createState() => _NetworkCheckPageState(); 12 | } 13 | 14 | /// 15 | /// State 16 | class _NetworkCheckPageState extends State { 17 | String _connectionStatus = 'Unknown'; 18 | final Connectivity _connectivity = Connectivity(); 19 | StreamSubscription? _connectivitySubscription; 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | initConnectivity(); 25 | _connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus); 26 | } 27 | 28 | @override 29 | void dispose() { 30 | _connectivitySubscription?.cancel(); 31 | super.dispose(); 32 | } 33 | 34 | // Platform messages are asynchronous, so we initialize in an async method. 35 | Future initConnectivity() async { 36 | ConnectivityResult result = ConnectivityResult.none; 37 | // Platform messages may fail, so we use a try/catch PlatformException. 38 | try { 39 | result = await _connectivity.checkConnectivity(); 40 | } on PlatformException catch (e) { 41 | print(e.toString()); 42 | } 43 | 44 | // If the widget was removed from the tree while the asynchronous platform 45 | // message was in flight, we want to discard the reply rather than calling 46 | // setState to update our non-existent appearance. 47 | if (!mounted) { 48 | return Future.value(null); 49 | } 50 | 51 | return _updateConnectionStatus(result); 52 | } 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | return Scaffold( 57 | appBar: AppBar( 58 | title: const Text('网络'), 59 | ), 60 | body: Center(child: Text('Connection Status: $_connectionStatus')), 61 | ); 62 | } 63 | 64 | Future _updateConnectionStatus(ConnectivityResult result) async { 65 | switch (result) { 66 | case ConnectivityResult.wifi: 67 | case ConnectivityResult.mobile: 68 | case ConnectivityResult.none: 69 | setState(() => _connectionStatus = result.toString()); 70 | break; 71 | default: 72 | setState(() => _connectionStatus = 'Failed to get connectivity.'); 73 | break; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/component/paint/sun_main_page.dart: -------------------------------------------------------------------------------- 1 | // import 'package:ai_sun/ai_sun.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// 5 | /// SunMainPage 6 | class SunMainPage extends StatefulWidget { 7 | @override 8 | _SunMainPageState createState() => _SunMainPageState(); 9 | } 10 | 11 | class _SunMainPageState extends State { 12 | var rangeValues = RangeValues(0.1, 0.5); 13 | 14 | double _max(double value) { 15 | return value * 100 * 2; 16 | } 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | appBar: AppBar(), 22 | ); 23 | // return Scaffold( 24 | // appBar: AppBar( 25 | // title: Text("custom painter page"), 26 | // ), 27 | // body: Column( 28 | // children: [ 29 | // AppTextHeadline6Widget.defaultStyle(data: "拖动滑轮右侧按钮预览自绘制组件的尺寸变动"), 30 | // Row( 31 | // children: [ 32 | // Expanded( 33 | // child: RangeSlider( 34 | // values: rangeValues, 35 | // divisions: 9, 36 | // labels: RangeLabels("${_max(rangeValues.start)}", "${_max(rangeValues.end)}"), 37 | // onChanged: (values) { 38 | // setState(() { 39 | // rangeValues = values; 40 | // }); 41 | // }, 42 | // ), 43 | // ) 44 | // ], 45 | // ), 46 | // Container( 47 | // width: _max(rangeValues.end), 48 | // height: _max(rangeValues.end), 49 | // child: CustomPaint( 50 | // foregroundPainter: AiSmilePainter.defaultStyle( 51 | // color: Colors.transparent, 52 | // ), 53 | // painter: AiSmilePainter.defaultStyle( 54 | // color: Colors.yellow, 55 | // ), 56 | // ), 57 | // ), 58 | // Divider( 59 | // height: 8, 60 | // ), 61 | // Container( 62 | // width: _max(rangeValues.end), 63 | // height: _max(rangeValues.end), 64 | // child: CustomPaint( 65 | // foregroundPainter: AiSunPainter.defaultStyle( 66 | // color: Colors.transparent, 67 | // ), 68 | // painter: AiSunPainter.defaultStyle( 69 | // color: Colors.yellow, 70 | // ), 71 | // ), 72 | // ), 73 | // Divider( 74 | // height: 8, 75 | // ), 76 | // Container( 77 | // width: _max(rangeValues.end), 78 | // height: _max(rangeValues.end), 79 | // child: CustomPaint( 80 | // foregroundPainter: AiSimpleSunPainter.defaultStyle( 81 | // color: Colors.transparent, 82 | // ), 83 | // painter: AiSimpleSunPainter.defaultStyle( 84 | // color: Colors.yellow, 85 | // ), 86 | // ), 87 | // ), 88 | // ], 89 | // ), 90 | // ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/component/personal/personal_face_widget.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | /// 6 | /// PersonalFaceWidget 7 | class PersonalFaceWidget extends StatefulWidget { 8 | PersonalFaceWidget.defaultStyle({Key? key}) : super(key: key); 9 | @override 10 | _PersonalFaceWidgetState createState() => _PersonalFaceWidgetState(); 11 | } 12 | 13 | class _PersonalFaceWidgetState extends State { 14 | @override 15 | Widget build(BuildContext context) { 16 | return Container( 17 | child: Center( 18 | child: Stack( 19 | alignment: Alignment.center, 20 | children: [ 21 | Image.asset( 22 | "assets/avatar.jpg", 23 | fit: BoxFit.cover, 24 | ), 25 | BackdropFilter( 26 | filter: ImageFilter.blur( 27 | sigmaX: 5, 28 | sigmaY: 5, 29 | ), 30 | child: Container( 31 | width: 1, 32 | height: 1, 33 | color: Colors.black.withOpacity(0), 34 | ), 35 | ), 36 | Container( 37 | margin: EdgeInsets.all(10), 38 | width: 100, 39 | height: 100, 40 | child: ClipOval( 41 | child: Image.asset( 42 | "assets/avatar.jpg", 43 | fit: BoxFit.cover, 44 | ), 45 | ), 46 | ), 47 | Positioned( 48 | left: 0, 49 | right: 0, 50 | bottom: 0, 51 | child: Row( 52 | mainAxisAlignment: MainAxisAlignment.center, 53 | children: [ 54 | Padding( 55 | child: Text( 56 | "Air", 57 | style: TextStyle( 58 | color: Theme.of(context).primaryColor, 59 | ), 60 | ), 61 | padding: EdgeInsets.all(10), 62 | ), 63 | ], 64 | ), 65 | ), 66 | ], 67 | ), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/component/route/launch_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:air_design/air_design.dart'; 4 | import 'package:airoute/airoute.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | /// 8 | /// LaunchPage 9 | class LaunchPage extends StatefulWidget with AirArgumentReceiver { 10 | dynamic _content = ""; 11 | @override 12 | void receive(AirArgument argument) { 13 | if (!AppStringHelper.isEmpty(argument.argument)) { 14 | _content = argument.argument['content']; 15 | } 16 | } 17 | 18 | @override 19 | State createState() { 20 | return _LaunchState(); 21 | } 22 | } 23 | 24 | /// _LaunchState 25 | class _LaunchState extends State { 26 | String _content = ""; 27 | @override 28 | Widget build(BuildContext context) { 29 | Size size = window.physicalSize; 30 | double width = size.width / window.devicePixelRatio; 31 | double height = size.height / window.devicePixelRatio; 32 | 33 | return Scaffold( 34 | appBar: AppBar( 35 | title: Text("First"), 36 | ), 37 | body: Column( 38 | mainAxisAlignment: MainAxisAlignment.center, 39 | crossAxisAlignment: CrossAxisAlignment.center, 40 | children: [ 41 | Spacer(), 42 | Spacer(), 43 | AppCardElevatedStyleWidget.defaultStyle( 44 | child: TextField( 45 | enabled: true, 46 | decoration: InputDecoration( 47 | icon: Text("参数"), 48 | prefixIcon: Icon(Icons.content_paste), 49 | ), 50 | onChanged: (String content) { 51 | _content = content; 52 | }, 53 | ), 54 | ), 55 | Spacer(), 56 | MaterialButton( 57 | onPressed: () { 58 | Airoute.pushNamedWithAnimation( 59 | routeName: "/route/SecondPage", 60 | argument: "$_content", 61 | routePageAnimation: AirouteTransition.Slide, 62 | ); 63 | }, 64 | color: Theme.of(context).primaryColor, 65 | textColor: Colors.white, 66 | child: Text("跳转下一页"), 67 | ), 68 | Spacer(), 69 | ], 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/component/route/second_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:airoute/airoute.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// 5 | /// SecondPage 6 | class SecondPage extends StatefulWidget with AirArgumentReceiver { 7 | dynamic _content; 8 | @override 9 | State createState() { 10 | return _SecondPageState(); 11 | } 12 | 13 | @override 14 | void receive(AirArgument argument) { 15 | _content = argument.argument; 16 | print("收到:${argument.argument}"); 17 | } 18 | } 19 | 20 | /// 21 | /// _SecondPageState 22 | class _SecondPageState extends State { 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | backgroundColor: Colors.blue, 27 | appBar: AppBar( 28 | elevation: 0, 29 | title: Text("Second"), 30 | ), 31 | body: Center( 32 | child: Column( 33 | children: [ 34 | Text( 35 | "以下为上页传递的数据\n\n\n${widget._content}", 36 | style: TextStyle( 37 | color: Colors.white, 38 | ), 39 | textAlign: TextAlign.center, 40 | ), 41 | RaisedButton.icon( 42 | onPressed: () { 43 | Airoute.pushNamed( 44 | routeName: "/route/ThirdPage", argument: "Air"); 45 | }, 46 | icon: Icon(Icons.arrow_right), 47 | label: Text("Next"), 48 | ), 49 | ], 50 | ), 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/component/route/third_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:airoute/airoute.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// 5 | /// ThirdPage 6 | class ThirdPage extends StatefulWidget with AirArgumentReceiver { 7 | dynamic _content; 8 | @override 9 | State createState() { 10 | return _ThirdPageState(); 11 | } 12 | 13 | @override 14 | void receive(AirArgument argument) { 15 | _content = argument.argument; 16 | print("收到:${argument.argument}"); 17 | } 18 | } 19 | 20 | /// 21 | /// _SecondPageState 22 | class _ThirdPageState extends State { 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | backgroundColor: Colors.blue, 27 | appBar: AppBar( 28 | elevation: 0, 29 | title: Text("Third"), 30 | ), 31 | body: Center( 32 | child: Column( 33 | children: [ 34 | Text( 35 | "以下为上页传递的数据\n\n\n${widget._content}", 36 | style: TextStyle( 37 | color: Colors.white, 38 | ), 39 | textAlign: TextAlign.center, 40 | ), 41 | ElevatedButton.icon( 42 | onPressed: () { 43 | Airoute.popUntil(untilRouteName: "/route/SecondPage"); 44 | }, 45 | icon: Icon(Icons.arrow_back), 46 | label: Text("Back"), 47 | ), 48 | ElevatedButton.icon( 49 | onPressed: () { 50 | Airoute.pushNamed( 51 | routeName: "/route/ThirdPage", argument: "Repeat"); 52 | }, 53 | icon: Icon(Icons.arrow_right), 54 | label: Text("Next"), 55 | ), 56 | ], 57 | ), 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/component/search/SearchPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// 5 | /// SearchPage 6 | class SearchPage extends StatefulWidget { 7 | @override 8 | State createState() { 9 | return _SearchState(); 10 | } 11 | } 12 | 13 | /// 14 | /// _SearchState 15 | class _SearchState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar(), 20 | body: Padding( 21 | padding: EdgeInsets.all(10), 22 | child: Column( 23 | children: [ 24 | TextField( 25 | style: TextStyle(background: Paint()..color = Colors.green), 26 | ) 27 | ], 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/component/setting/setting_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:airoute/airoute.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_app_sample/common/helper/tip_helper.dart'; 6 | import 'package:flutter_app_sample/component/personal/personal_face_widget.dart'; 7 | 8 | /// 9 | /// SettingPage 10 | class SettingPage extends StatefulWidget { 11 | @override 12 | _SettingPageState createState() => _SettingPageState(); 13 | } 14 | 15 | class _SettingPageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: Text("设置"), 21 | ), 22 | body: Column( 23 | children: [ 24 | AppCardElevatedStyleWidget.defaultStyle( 25 | child: PersonalFaceWidget.defaultStyle(), 26 | ), 27 | AppCardOutlinedStyleWidget.defaultStyle( 28 | onTap: () { 29 | setState(() { 30 | TipHelper.showTip(context: context, message: "努力开发中..."); 31 | }); 32 | }, 33 | child: ListTile( 34 | title: Text("常亮"), 35 | trailing: IgnorePointer( 36 | ignoring: true, 37 | child: Switch( 38 | value: false, 39 | onChanged: (bool value) { 40 | setState(() {}); 41 | }, 42 | ), 43 | )), 44 | ), 45 | AppCardOutlinedStyleWidget.defaultStyle( 46 | onTap: () { 47 | Airoute.pushNamed( 48 | routeName: "/AirLicensePage", 49 | ); 50 | }, 51 | child: ListTile( 52 | leading: Text("版权/证书"), 53 | trailing: Icon(Icons.arrow_right), 54 | ), 55 | ), 56 | AppCardOutlinedStyleWidget.defaultStyle( 57 | onTap: () { 58 | showCupertinoDialog( 59 | context: context, 60 | builder: (BuildContext context) { 61 | return CupertinoAlertDialog( 62 | title: Text("退出登陆"), 63 | content: Text("确定退出登陆"), 64 | actions: [ 65 | CupertinoDialogAction( 66 | onPressed: () { 67 | Airoute.pop(); 68 | }, 69 | child: Text("取消"), 70 | ), 71 | CupertinoDialogAction( 72 | onPressed: () { 73 | Airoute.pushNamedAndRemoveUntil(newRouteName: "/LoginPage"); 74 | }, 75 | child: Text("确定"), 76 | ), 77 | ], 78 | ); 79 | }); 80 | }, 81 | child: ListTile( 82 | leading: Text("退出登陆"), 83 | trailing: Icon(Icons.exit_to_app), 84 | ), 85 | ), 86 | ], 87 | ), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/component/shop/Product.dart: -------------------------------------------------------------------------------- 1 | class Product { 2 | const Product({required this.name, required this.originPrice, required this.nowPrice}); 3 | final String name; 4 | final String originPrice; 5 | final String nowPrice; 6 | } 7 | -------------------------------------------------------------------------------- /lib/component/shop/ShoppingList.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/component/shop/Product.dart'; 3 | import 'package:flutter_app_sample/component/shop/ShoppingListItem.dart'; 4 | 5 | ///商品列表 6 | class ShoppingListPage extends StatefulWidget { 7 | @override 8 | State createState() { 9 | return _ShoppingState(); 10 | } 11 | } 12 | 13 | class _ShoppingState extends State { 14 | Set _shoppingCart = Set(); 15 | 16 | final List products = [ 17 | Product(name: "product", originPrice: "100", nowPrice: "59"), 18 | ]; 19 | 20 | Widget createWidget() { 21 | return ListView.builder( 22 | itemBuilder: (BuildContext context, int position) { 23 | return ShoppingListItem( 24 | product: products[position], 25 | inCart: true, 26 | onCartChanged: _handleCartChanged, 27 | ); 28 | }, 29 | padding: EdgeInsets.all(5.0), 30 | itemCount: products.length, 31 | ); 32 | } 33 | 34 | void _handleCartChanged(Product product, bool inCart) { 35 | setState(() { 36 | if (!inCart) 37 | _shoppingCart.remove(product); 38 | else 39 | _shoppingCart.remove(product); 40 | 41 | print("点击了!${product} ${inCart},${products.length}"); 42 | }); 43 | } 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | return createWidget(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/component/shop/ShoppingListItem.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/component/shop/Product.dart'; 3 | 4 | ///ShoppingListItem 5 | ///支持:Scroll Item remove item! 6 | typedef void CartChangedCallback(Product product, bool inCart); 7 | 8 | class ShoppingListItem extends StatefulWidget { 9 | ShoppingListItem({ 10 | required Product product, 11 | required this.inCart, 12 | required this.onCartChanged, 13 | }) : product = product; 14 | 15 | final Product product; 16 | final bool inCart; 17 | final CartChangedCallback onCartChanged; 18 | 19 | @override 20 | State createState() { 21 | return _ShoppingListItem( 22 | product: product, 23 | inCart: inCart, 24 | onCartChanged: onCartChanged, 25 | ); 26 | } 27 | } 28 | 29 | class _ShoppingListItem extends State { 30 | final Product product; 31 | final bool inCart; 32 | final CartChangedCallback onCartChanged; 33 | 34 | _ShoppingListItem({ 35 | required Product product, 36 | required this.inCart, 37 | required this.onCartChanged, 38 | }) : product = product; 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | ///Dismissible-侧滑! 43 | ///Scaffold.of(context).showSnackBar(...)-SnackBar! 44 | return Dismissible( 45 | key: Key("${product.name}"), 46 | onDismissed: (DismissDirection direction) { 47 | //这个和Android的SnackBar差不多 48 | Scaffold.of(context).showSnackBar(SnackBar( 49 | content: new Text("${product.name} dismissed"), 50 | action: SnackBarAction( 51 | label: "撤销", 52 | onPressed: () { 53 | print("触发Snackbar动作!"); 54 | }), 55 | )); 56 | }, 57 | child: Card( 58 | elevation: 2.0, 59 | margin: EdgeInsets.all(5.0), 60 | child: ListTile( 61 | leading: CircleAvatar( 62 | child: Text("${product.name[0]}"), 63 | ), 64 | title: Text( 65 | "${product.nowPrice}", 66 | style: TextStyle( 67 | color: _getColor(context), 68 | ), 69 | ), 70 | subtitle: Text( 71 | "${product.originPrice}", 72 | style: _getTextStyle(context), 73 | ), 74 | contentPadding: EdgeInsets.all(10.0), 75 | selected: false, 76 | trailing: Text( 77 | "${product.name}", 78 | style: TextStyle( 79 | color: Theme.of(context).primaryColor, 80 | ), 81 | ), 82 | onTap: () { 83 | onCartChanged(product, !inCart); 84 | }, 85 | ), 86 | )); 87 | } 88 | 89 | Color _getColor(BuildContext context) { 90 | return inCart ? Colors.black54 : Theme.of(context).primaryColor; 91 | } 92 | 93 | TextStyle _getTextStyle(BuildContext context) { 94 | if (!inCart) return TextStyle(); 95 | 96 | return TextStyle( 97 | color: Colors.black54, 98 | decoration: TextDecoration.lineThrough, 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /lib/component/state/FrogColor.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FrogColor extends InheritedWidget { 4 | const FrogColor({ 5 | Key? key, 6 | required this.color, 7 | required Widget child, 8 | }) : super(key: key, child: child); 9 | 10 | final Color color; 11 | 12 | static FrogColor of(BuildContext context) { 13 | final FrogColor? result = context.dependOnInheritedWidgetOfExactType(); 14 | assert(result != null, 'No FrogColor found in context'); 15 | return result!; 16 | } 17 | 18 | @override 19 | bool updateShouldNotify(FrogColor old) => color != old.color; 20 | } 21 | -------------------------------------------------------------------------------- /lib/component/state/inherited_widget_child.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// InheritedWidgetChild 5 | class InheritedWidgetChild extends InheritedWidget { 6 | final String name; 7 | 8 | InheritedWidgetChild({ 9 | Key? key, 10 | required this.name, 11 | required Widget child, 12 | }) : super(key: key, child: child) {} 13 | 14 | @override 15 | bool updateShouldNotify(covariant InheritedWidgetChild oldWidget) { 16 | return this.name != oldWidget.name; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/component/state/user_info.dart: -------------------------------------------------------------------------------- 1 | class UserInfo { 2 | String name; 3 | int age; 4 | 5 | UserInfo({required this.name, required this.age}); 6 | 7 | @override 8 | bool operator ==(Object other) { 9 | if (other is UserInfo) { 10 | return name == other.name && age == other.age; 11 | } else { 12 | return false; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/component/state/user_inherited_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/component/state/user_info.dart'; 3 | 4 | class UserInheritedWidget extends InheritedWidget { 5 | final UserInfo userInfo; 6 | 7 | UserInheritedWidget({required this.userInfo, required Widget child}) : super(child: child); 8 | 9 | static UserInheritedWidget of(BuildContext context) { 10 | return context.dependOnInheritedWidgetOfExactType()!; 11 | } 12 | 13 | @override 14 | bool updateShouldNotify(covariant UserInheritedWidget oldWidget) { 15 | return oldWidget.userInfo != userInfo; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/component/tab/navigation_drawer_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// 5 | /// NavigationDrawerPage 6 | class NavigationDrawerPage extends StatefulWidget { 7 | const NavigationDrawerPage({Key? key}) : super(key: key); 8 | 9 | @override 10 | _NavigationDrawerPageState createState() => _NavigationDrawerPageState(); 11 | } 12 | 13 | class _NavigationDrawerPageState extends State { 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | appBar: AppBar( 18 | title: const Text('Drawer Demo'), 19 | leading: BackButton(), 20 | ), 21 | endDrawer: Drawer( 22 | child: ListView( 23 | padding: EdgeInsets.zero, 24 | children: const [ 25 | DrawerHeader( 26 | decoration: BoxDecoration( 27 | color: Colors.blue, 28 | ), 29 | child: Text( 30 | 'Drawer Header', 31 | style: TextStyle( 32 | color: Colors.white, 33 | fontSize: 24, 34 | ), 35 | ), 36 | ), 37 | ListTile( 38 | leading: Icon(Icons.message), 39 | title: Text('Messages'), 40 | ), 41 | ListTile( 42 | leading: Icon(Icons.account_circle), 43 | title: Text('Profile'), 44 | ), 45 | ListTile( 46 | leading: Icon(Icons.settings), 47 | title: Text('Settings'), 48 | ), 49 | ], 50 | ), 51 | ), 52 | body: Builder(builder: (context) { 53 | return Center( 54 | child: AppCardOutlinedStyleWidget.defaultStyle( 55 | onTap: () { 56 | Scaffold.of(context).openEndDrawer(); 57 | }, 58 | child: Text("open draw widget"), 59 | ), 60 | ); 61 | }), 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/component/tab/navigation_rail_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// NavigationRailPage 5 | class NavigationRailPage extends StatefulWidget { 6 | const NavigationRailPage({Key? key}) : super(key: key); 7 | 8 | @override 9 | _NavigationRailPageState createState() => _NavigationRailPageState(); 10 | } 11 | 12 | class _NavigationRailPageState extends State { 13 | final List _list = [ 14 | { 15 | "icon": Icon(Icons.favorite_border), 16 | "selectedIcon": Icon(Icons.favorite), 17 | "label": Text('First'), 18 | }, 19 | { 20 | "icon": Icon(Icons.bookmark_border), 21 | "selectedIcon": Icon(Icons.book), 22 | "label": Text('Second'), 23 | }, 24 | { 25 | "icon": Icon(Icons.star_border), 26 | "selectedIcon": Icon(Icons.star), 27 | "label": Text('Third'), 28 | }, 29 | ]; 30 | int _selectedIndex = 0; 31 | bool _extended = false; 32 | @override 33 | Widget build(BuildContext context) { 34 | return Scaffold( 35 | appBar: AppBar( 36 | title: Text("NavigationRail"), 37 | ), 38 | body: Row( 39 | children: [ 40 | NavigationRail( 41 | leading: Row( 42 | mainAxisAlignment: MainAxisAlignment.end, 43 | children: [ 44 | IconButton( 45 | tooltip: "菜单", 46 | onPressed: () { 47 | setState(() { 48 | _extended = !_extended; 49 | }); 50 | }, 51 | icon: Icon(Icons.menu)), 52 | ], 53 | ), 54 | destinations: [for (int railIndex = 0, railSize = _list.length; railIndex < railSize; railIndex++) NavigationRailDestination(icon: _list[railIndex]['icon'], selectedIcon: _list[railIndex]['selectedIcon'], label: _list[railIndex]['label'])], 55 | selectedIndex: _selectedIndex, 56 | onDestinationSelected: (int selectedIndex) { 57 | setState(() { 58 | _selectedIndex = selectedIndex; 59 | }); 60 | }, 61 | labelType: _extended ? NavigationRailLabelType.none : NavigationRailLabelType.all, 62 | extended: _extended, 63 | ), 64 | const VerticalDivider(thickness: 1, width: 1), 65 | Expanded( 66 | child: Row( 67 | mainAxisAlignment: MainAxisAlignment.center, 68 | children: [ 69 | Container( 70 | child: _list[_selectedIndex]['selectedIcon'], 71 | ), 72 | Text("selectedIndex:$_selectedIndex"), 73 | ], 74 | ), 75 | ), 76 | ], 77 | ), 78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/component/tab/tab_main_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:airoute/airoute.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | /// 6 | /// TabMainPage 7 | class TabMainPage extends StatefulWidget { 8 | const TabMainPage({Key? key}) : super(key: key); 9 | 10 | @override 11 | _TabMainPageState createState() => _TabMainPageState(); 12 | } 13 | 14 | class _TabMainPageState extends State { 15 | final List list = [ 16 | { 17 | "name": "NavigationRail widget", 18 | "routeName": "/TabMainPage/NavigationRailPage", 19 | }, 20 | { 21 | "name": "Navigation Drawer widget", 22 | "routeName": "/TabMainPage/NavigationDrawerPage", 23 | }, 24 | ]; 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | appBar: AppBar( 29 | title: Text("Tab & Navigation"), 30 | ), 31 | body: ListView.builder( 32 | physics: BouncingScrollPhysics(), 33 | itemCount: list.length, 34 | itemBuilder: (BuildContext context, int index) { 35 | return AppCardOutlinedStyleWidget.defaultStyle( 36 | onTap: () { 37 | Airoute.pushNamed(routeName: "${list[index]['routeName']}"); 38 | }, 39 | child: Padding( 40 | padding: EdgeInsets.all(16), 41 | child: AppTextHeadline6Widget.defaultStyle(data: "${list[index]['name']}"), 42 | ), 43 | ); 44 | }), 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/component/test/TestPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | ///用于测试 4 | @deprecated 5 | class TestPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return _TestState(); 9 | } 10 | } 11 | 12 | /// 13 | /// _TestState 14 | class _TestState extends State { 15 | Widget createWidget() { 16 | return Center( 17 | child: Text("Center!"), 18 | ); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return createWidget(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/data/Read: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/lib/data/Read -------------------------------------------------------------------------------- /lib/data/request/LoginRequestBean.dart: -------------------------------------------------------------------------------- 1 | 2 | class LoginRequestBean{ 3 | 4 | } -------------------------------------------------------------------------------- /lib/data/response/User.dart: -------------------------------------------------------------------------------- 1 | class User { 2 | int status = 0; 3 | String message = ""; 4 | } 5 | -------------------------------------------------------------------------------- /lib/di/Read: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/lib/di/Read -------------------------------------------------------------------------------- /lib/entrance_global_config.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// EntranceGlobalConfig 3 | class EntranceGlobalConfig { 4 | /// 5 | /// isTvEntrance 6 | static bool isTvEntrance() { 7 | return false; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/generated_plugin_registrant.dart: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // ignore_for_file: directives_ordering 6 | // ignore_for_file: lines_longer_than_80_chars 7 | // ignore_for_file: depend_on_referenced_packages 8 | 9 | import 'package:ai_barcode_web/ai_barcode_web.dart'; 10 | import 'package:connectivity_plus_web/connectivity_plus_web.dart'; 11 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; 12 | import 'package:image_picker_for_web/image_picker_for_web.dart'; 13 | import 'package:shared_preferences_web/shared_preferences_web.dart'; 14 | import 'package:url_launcher_web/url_launcher_web.dart'; 15 | import 'package:video_player_web/video_player_web.dart'; 16 | 17 | // ignore: public_member_api_docs 18 | void registerPlugins(Registrar registrar) { 19 | AiBarcodeWebPlugin.registerWith(registrar); 20 | ConnectivityPlusPlugin.registerWith(registrar); 21 | ImagePickerPlugin.registerWith(registrar); 22 | SharedPreferencesPlugin.registerWith(registrar); 23 | UrlLauncherPlugin.registerWith(registrar); 24 | VideoPlayerPlugin.registerWith(registrar); 25 | registrar.registerMessageHandler(); 26 | } 27 | -------------------------------------------------------------------------------- /lib/global_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// GlobalViewModel 5 | class GlobalViewModel extends ChangeNotifier { 6 | static GlobalViewModel? _globalViewModel; 7 | 8 | ThemeMode _themeMode = ThemeMode.system; 9 | 10 | GlobalViewModel._(); 11 | 12 | /// 13 | /// Instance 14 | static GlobalViewModel getInstance() { 15 | if (_globalViewModel == null) { 16 | _globalViewModel = GlobalViewModel._(); 17 | } 18 | return _globalViewModel!; 19 | } 20 | 21 | /// 22 | /// LightTheme 23 | ThemeMode toggleLightThemeMode() { 24 | _themeMode = ThemeMode.light; 25 | //notify listeners adapter 26 | notifyListeners(); 27 | return _themeMode; 28 | } 29 | 30 | /// 31 | /// DarkTheme 32 | ThemeMode toggleDarkThemeMode() { 33 | _themeMode = ThemeMode.dark; 34 | //notify listeners adapter 35 | notifyListeners(); 36 | return _themeMode; 37 | } 38 | 39 | /// 40 | /// SystemTheme 41 | ThemeMode toggleSystemThemeMode() { 42 | _themeMode = ThemeMode.system; 43 | //notify listeners adapter 44 | notifyListeners(); 45 | return _themeMode; 46 | } 47 | 48 | /// Toggle theme mode 49 | /// ToggleTheme(one of 'DarkTheme or LightTheme') 50 | ThemeMode toggleThemeMode() { 51 | _themeMode = _themeMode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark; 52 | //notify listeners adapter 53 | notifyListeners(); 54 | return _themeMode; 55 | } 56 | 57 | ThemeMode get themeMode => _themeMode; 58 | 59 | bool get isDarkTheme => _themeMode == ThemeMode.dark; 60 | 61 | bool get isLightTheme => _themeMode == ThemeMode.light; 62 | 63 | bool get isSystemTheme => _themeMode == ThemeMode.system; 64 | } 65 | -------------------------------------------------------------------------------- /lib/sample/ViewPagerFragmentPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// ViewPagerFragmentPage 5 | class ViewPagerFragmentPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return _ViewPagerState(); 9 | } 10 | } 11 | 12 | /// 13 | /// _ViewPagerState 14 | class _ViewPagerState extends State { 15 | Widget createWidget() { 16 | return DefaultTabController( 17 | length: choices.length, 18 | child: Scaffold( 19 | appBar: AppBar( 20 | title: const Text('Tabbed AppBar'), 21 | bottom: TabBar( 22 | isScrollable: true, 23 | tabs: choices.map((Choice choice) { 24 | return Tab( 25 | text: choice.title, 26 | icon: Icon(choice.icon), 27 | ); 28 | }).toList(), 29 | ), 30 | ), 31 | body: TabBarView( 32 | children: choices.map((Choice choice) { 33 | return Padding( 34 | padding: const EdgeInsets.all(16.0), 35 | child: ChoiceCard( 36 | choice: choice, 37 | key: GlobalObjectKey("value"), 38 | ), 39 | ); 40 | }).toList(), 41 | ), 42 | ), 43 | ); 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | return createWidget(); 49 | } 50 | } 51 | 52 | class Choice { 53 | const Choice({required this.title, required this.icon}); 54 | 55 | final String title; 56 | final IconData icon; 57 | } 58 | 59 | const List choices = const [ 60 | const Choice(title: 'CAR', icon: Icons.directions_car), 61 | const Choice(title: 'BICYCLE', icon: Icons.directions_bike), 62 | const Choice(title: 'BOAT', icon: Icons.directions_boat), 63 | const Choice(title: 'BUS', icon: Icons.directions_bus), 64 | const Choice(title: 'TRAIN', icon: Icons.directions_railway), 65 | const Choice(title: 'WALK', icon: Icons.directions_walk), 66 | ]; 67 | 68 | class ChoiceCard extends StatelessWidget { 69 | const ChoiceCard({required Key key, required this.choice}) : super(key: key); 70 | 71 | final Choice choice; 72 | 73 | @override 74 | Widget build(BuildContext context) { 75 | final TextStyle textStyle = Theme.of(context).textTheme.displayMedium!; 76 | return Card( 77 | color: Colors.white, 78 | child: Center( 79 | child: Column( 80 | mainAxisSize: MainAxisSize.min, 81 | crossAxisAlignment: CrossAxisAlignment.center, 82 | children: [ 83 | Icon(choice.icon, size: 128.0, color: textStyle.color), 84 | Text(choice.title, style: textStyle), 85 | ], 86 | ), 87 | ), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/sample/anim/AnimatedContainerPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// AnimatedContainerPage 5 | class AnimatedContainerPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return _AnimatedContainerState(); 9 | } 10 | } 11 | 12 | /// 13 | /// _AnimatedContainerState 14 | class _AnimatedContainerState extends State { 15 | var _titleName = "AnimatedContainer"; 16 | bool selected = false; 17 | 18 | int durationUnitSecond = 2; 19 | 20 | Widget createWidget() { 21 | return GestureDetector( 22 | onTap: () { 23 | setState(() { 24 | selected = !selected; 25 | }); 26 | }, 27 | child: Column( 28 | children: [ 29 | /// 30 | /// AnimatedContainer演示效果 31 | /// 32 | Center( 33 | child: AnimatedContainer( 34 | width: selected ? 300.0 : 200.0, 35 | height: selected ? 200.0 : 300.0, 36 | color: selected ? Colors.red : Colors.blue, 37 | alignment: 38 | selected ? Alignment.center : AlignmentDirectional.topCenter, 39 | duration: Duration(seconds: durationUnitSecond), 40 | curve: Curves.fastOutSlowIn, 41 | child: Column( 42 | children: [ 43 | FlutterLogo(size: 75), 44 | Text( 45 | "Flutter's AnimatedContainer!", 46 | style: TextStyle(color: Colors.white), 47 | ), 48 | Text( 49 | "click the rect to show anim!", 50 | style: TextStyle(color: Colors.white), 51 | ), 52 | RaisedButton( 53 | animationDuration: Duration(seconds: durationUnitSecond), 54 | shape: RoundedRectangleBorder( 55 | borderRadius: BorderRadius.circular(selected ? 15 : 0), 56 | ), 57 | child: Text("AnimatedContainerPage"), 58 | onPressed: () {}, 59 | ), 60 | ], 61 | ), 62 | ), 63 | ), 64 | 65 | /// 66 | /// 以下说明AnimatedContainer的限制场景 67 | /// 68 | AnimatedContainer( 69 | width: 200.0, 70 | height: 200.0, 71 | color: selected ? Colors.red : Colors.blue, 72 | duration: Duration(seconds: durationUnitSecond), 73 | curve: Curves.fastOutSlowIn, 74 | child: Container( 75 | width: 200, 76 | height: 200, 77 | child: Text( 78 | "请注意这段文字:AnimatedContainer只能为AnimatedContainer自身设置动画(自身不包括AnimatedContainer的child,以及更深层次的child...\n这是AnimatedContainer的限制和短处)", 79 | style: TextStyle( 80 | color: selected ? Colors.white : Colors.black, 81 | ), 82 | ), 83 | ), 84 | ), 85 | ], 86 | ), 87 | ); 88 | } 89 | 90 | @override 91 | Widget build(BuildContext context) { 92 | return Scaffold( 93 | appBar: AppBar( 94 | title: Text("$_titleName"), 95 | ), 96 | body: createWidget(), 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/sample/anim/AppPageRoute.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppPageRoute extends PageRoute { 4 | @override 5 | Color get barrierColor => Colors.white; 6 | 7 | @override 8 | String get barrierLabel => "null"; 9 | 10 | @override 11 | Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { 12 | return Container(); 13 | } 14 | 15 | @override 16 | bool get maintainState => false; 17 | 18 | @override 19 | Duration get transitionDuration => Duration(); 20 | } 21 | -------------------------------------------------------------------------------- /lib/sample/anim/ColorTweenPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | ///ColorTweenPage 5 | ///from one color to another color! 6 | /// 7 | class ColorTweenPage extends StatefulWidget { 8 | @override 9 | State createState() { 10 | return _ColorTweenState(); 11 | } 12 | } 13 | 14 | /// 15 | /// _ColorTweenState 16 | class _ColorTweenState extends State { 17 | String _titleName = "ColorTween"; 18 | 19 | ///0.0 ... 1.0 20 | double _colorTweenTransform = 0.0; 21 | 22 | double _rangeMin = 0.0; 23 | double _rangeMax = 1.0; 24 | double _rangeStart = 0.0; 25 | double _rangeEnd = 1.0; 26 | double _rangeUnit = 0.1; 27 | int _rangeDivisions = 100; 28 | 29 | Widget createWidget() { 30 | return Column( 31 | children: [ 32 | Container( 33 | color: ColorTween(begin: Colors.red, end: Colors.blue) 34 | .transform(_colorTweenTransform), 35 | width: 300, 36 | height: 300, 37 | alignment: Alignment.center, 38 | child: Text( 39 | "ColorTween", 40 | style: TextStyle( 41 | color: Colors.white, 42 | ), 43 | textAlign: TextAlign.center, 44 | ), 45 | ), 46 | RangeSlider( 47 | divisions: _rangeDivisions, 48 | labels: RangeLabels("$_rangeStart", "$_rangeEnd"), 49 | min: _rangeMin, 50 | max: _rangeMax, 51 | values: RangeValues(_rangeStart, _rangeEnd), 52 | onChanged: (RangeValues values) { 53 | /* 54 | Render 55 | */ 56 | setState(() { 57 | _rangeStart = values.start; 58 | _colorTweenTransform = _rangeStart; 59 | }); 60 | }, 61 | ), 62 | ], 63 | ); 64 | } 65 | 66 | @override 67 | Widget build(BuildContext context) { 68 | return Scaffold( 69 | appBar: AppBar( 70 | title: Text("$_titleName"), 71 | ), 72 | body: createWidget(), 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/sample/anim/FadeInImagePage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// FadeInImagePage 5 | /// (用于:加载网络图片,以及等待时的占位符) 6 | class FadeInImagePage extends StatefulWidget { 7 | @override 8 | State createState() { 9 | return _FadeInImageState(); 10 | } 11 | } 12 | 13 | /// 14 | /// _FadeInImageState 15 | class _FadeInImageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: Text("FadeInImage"), 21 | ), 22 | body: Column( 23 | children: [ 24 | FadeInImage( 25 | placeholder: NetworkImage( 26 | "http://img1.imgtn.bdimg.com/it/u=2052832277,3734439426&fm=26&gp=0.jpg"), 27 | image: NetworkImage( 28 | "http://img3.imgtn.bdimg.com/it/u=4127304152,1726929467&fm=26&gp=0.jpg"), 29 | ), 30 | ], 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/sample/anim/HeroAnimPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/sample/CollapsingToolbarPage.dart'; 3 | 4 | /// 5 | /// HeroAnimPage 6 | /// 过渡动画 7 | /// 8 | class HeroAnimPage extends StatefulWidget { 9 | @override 10 | State createState() { 11 | return _HeroAnimState(); 12 | } 13 | } 14 | 15 | /// 16 | /// _HeroAnimState 17 | class _HeroAnimState extends State { 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | appBar: AppBar( 22 | title: Text("Hero animation"), 23 | ), 24 | body: Center( 25 | child: GestureDetector( 26 | onTap: () { 27 | /* 28 | 为Hero动画加"透明动画的页面切换" 29 | */ 30 | Navigator.push(context, PageRouteBuilder(pageBuilder: 31 | (BuildContext context, Animation animation, 32 | Animation secondaryAnimation) { 33 | return FadeTransition( 34 | opacity: animation, 35 | child: CollapsingToolbarPage(), 36 | ); 37 | })); 38 | }, 39 | child: Card( 40 | color: Colors.blue, 41 | child: Column( 42 | children: [ 43 | Hero( 44 | tag: "hero_image", 45 | child: Image.asset( 46 | "assets/pexels-photo-396547.jpg", 47 | fit: BoxFit.cover, 48 | ), 49 | ), 50 | Hero( 51 | tag: "hero_text", 52 | child: Text( 53 | "点击我,查看Hero效果", 54 | style: TextStyle( 55 | color: Colors.white, 56 | backgroundColor: Colors.blue, 57 | ), 58 | ), 59 | ), 60 | ], 61 | ), 62 | ), 63 | ), 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/sample/anim/OpacityAndAnimatedOpacityPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// Opacity 5 | /// AnimatedOpacity 6 | class OpacityAndAnimatedOpacityPage extends StatefulWidget { 7 | @override 8 | State createState() { 9 | return _OpacityAndAnimatedOpacityState(); 10 | } 11 | } 12 | 13 | /// 14 | /// _OpacityAndAnimatedOpacityState 15 | class _OpacityAndAnimatedOpacityState 16 | extends State { 17 | var _rangeStart = 40.0; 18 | var _rangeEnd = 100.0; 19 | 20 | var _rangeMin = 1.0; 21 | var _rangeMax = 100.0; 22 | 23 | double _opacity = 1.0; 24 | 25 | double opacityLevel = 1.0; 26 | 27 | void _changeOpacity() { 28 | setState(() { 29 | opacityLevel = opacityLevel == 0 ? 1.0 : 0.0; 30 | }); 31 | } 32 | 33 | Widget createWidget() { 34 | return SingleChildScrollView( 35 | child: Column( 36 | children: [ 37 | Text("Opacity: $_opacity"), 38 | Opacity( 39 | opacity: _opacity, 40 | child: Column( 41 | children: [ 42 | FlutterLogo( 43 | size: 300, 44 | ), 45 | Text("Opacity"), 46 | ], 47 | ), 48 | ), 49 | RangeSlider( 50 | values: RangeValues(_rangeStart, _rangeEnd), 51 | min: _rangeMin, 52 | max: _rangeMax, 53 | divisions: 100, //把总数分为divisions份 54 | labels: 55 | RangeLabels("${_rangeStart.toInt()}", "${_rangeEnd.toInt()}"), 56 | onChanged: (RangeValues values) { 57 | /* 58 | update 59 | */ 60 | setState(() { 61 | _rangeStart = values.start; 62 | //_rangeEnd = values.end; 63 | _opacity = _rangeStart / 100; 64 | }); 65 | }, 66 | ), 67 | 68 | /* 69 | Animated Opacity 70 | */ 71 | AnimatedOpacity( 72 | opacity: opacityLevel, 73 | duration: Duration(seconds: 2), 74 | child: Column( 75 | children: [ 76 | FlutterLogo( 77 | size: 200, 78 | ), 79 | Text("AnimatedOpacity"), 80 | ], 81 | ), 82 | ), 83 | RaisedButton( 84 | textColor: Colors.white, 85 | color: Colors.blue, 86 | child: Text("Fade Logo"), 87 | onPressed: () { 88 | _changeOpacity(); 89 | }, 90 | ), 91 | ], 92 | ), 93 | ); 94 | } 95 | 96 | @override 97 | Widget build(BuildContext context) { 98 | return Scaffold( 99 | appBar: AppBar( 100 | title: Text("OpacityAndAnimatedOpacityPage"), 101 | ), 102 | body: createWidget(), 103 | ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/sample/anim/icon/main_icon_anim_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// MainIconAnimPage 4 | /// Icons with animation 5 | class MainIconAnimPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return _MainIconAnimState(); 9 | } 10 | } 11 | 12 | class _MainIconAnimState extends State with SingleTickerProviderStateMixin { 13 | late AnimationController _animationController; 14 | @override 15 | void initState() { 16 | super.initState(); 17 | _animationController = AnimationController(vsync: this); 18 | _animationController.duration = Duration(seconds: 1); 19 | } 20 | 21 | @override 22 | void dispose() { 23 | super.dispose(); 24 | _animationController.stop(); 25 | _animationController.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | appBar: AppBar( 32 | title: Text("IconAnim"), 33 | ), 34 | body: Row( 35 | children: [ 36 | Spacer(), 37 | Column( 38 | children: [ 39 | Spacer(), 40 | AnimatedIcon(icon: AnimatedIcons.menu_arrow, progress: _animationController), 41 | AnimatedIcon(icon: AnimatedIcons.play_pause, progress: _animationController), 42 | AnimatedIcon(icon: AnimatedIcons.pause_play, progress: _animationController), 43 | AnimatedIcon(icon: AnimatedIcons.add_event, progress: _animationController), 44 | AnimatedIcon(icon: AnimatedIcons.arrow_menu, progress: _animationController), 45 | AnimatedIcon(icon: AnimatedIcons.close_menu, progress: _animationController), 46 | AnimatedIcon(icon: AnimatedIcons.ellipsis_search, progress: _animationController), 47 | AnimatedIcon(icon: AnimatedIcons.event_add, progress: _animationController), 48 | AnimatedIcon(icon: AnimatedIcons.home_menu, progress: _animationController), 49 | AnimatedIcon(icon: AnimatedIcons.list_view, progress: _animationController), 50 | AnimatedIcon(icon: AnimatedIcons.menu_close, progress: _animationController), 51 | AnimatedIcon(icon: AnimatedIcons.menu_home, progress: _animationController), 52 | AnimatedIcon(icon: AnimatedIcons.menu_arrow, progress: _animationController), 53 | AnimatedIcon(icon: AnimatedIcons.view_list, progress: _animationController), 54 | Spacer(), 55 | ], 56 | ), 57 | Spacer(), 58 | ], 59 | ), 60 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, 61 | floatingActionButton: FloatingActionButton( 62 | onPressed: () { 63 | if (_animationController.isAnimating || _animationController.isCompleted) { 64 | _animationController.reverse(); 65 | } else { 66 | _animationController.forward(); 67 | } 68 | }, 69 | child: AnimatedIcon(icon: AnimatedIcons.play_pause, progress: _animationController), 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/sample/anim/snappable_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | // import 'package:snappable/snappable.dart'; 3 | 4 | /// 5 | /// AnappablePage 6 | class AnappablePage extends StatefulWidget { 7 | @override 8 | State createState() { 9 | return _AnappableState(); 10 | } 11 | } 12 | 13 | /// 14 | /// _AnappableState 15 | class _AnappableState extends State { 16 | // final _snappableKey = GlobalKey(); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Scaffold( 21 | appBar: AppBar(), 22 | ); 23 | // return Scaffold( 24 | // appBar: AppBar( 25 | // title: Text("Anappable anim"), 26 | // ), 27 | // body: Column( 28 | // children: [ 29 | // Snappable( 30 | // key: _snappableKey, 31 | // snapOnTap: true, 32 | // child: Card( 33 | // child: Container( 34 | // height: 300, 35 | // width: double.infinity, 36 | // alignment: Alignment.center, 37 | // child: Image.asset( 38 | // "assets/pexels-photo-396547.jpg", 39 | // fit: BoxFit.cover, 40 | // ), 41 | // ), 42 | // ), 43 | // ), 44 | // ], 45 | // ), 46 | // floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, 47 | // floatingActionButton: FloatingActionButton( 48 | // onPressed: () { 49 | // SnappableState state = _snappableKey.currentState; 50 | // if (state.isGone) { 51 | // state.reset(); 52 | // } else { 53 | // state.snap(); 54 | // } 55 | // }, 56 | // child: Icon(Icons.play_arrow), 57 | // ), 58 | // ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/sample/chart/bar_chart/bar_chart_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BarChartPage extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Container( 7 | color: const Color(0xff232040), 8 | child: Center( 9 | child: Padding( 10 | padding: const EdgeInsets.all(28.0), 11 | // child: BarChartSample1(), 12 | child: Container()), 13 | ), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/sample/chart/bar_chart/bar_chart_page2.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BarChartPage2 extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Container( 7 | color: const Color(0xff132240), 8 | child: Center( 9 | child: Padding( 10 | padding: const EdgeInsets.all(28.0), 11 | // child: BarChartSample2(), 12 | child: Container(), 13 | ), 14 | ), 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/sample/chart/line_chart/line_chart_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LineChartPage extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Container( 7 | color: const Color(0xff262545), 8 | child: ListView( 9 | children: [ 10 | Align( 11 | alignment: Alignment.centerLeft, 12 | child: Padding( 13 | padding: const EdgeInsets.only( 14 | left: 36.0, 15 | top: 24, 16 | ), 17 | child: Text( 18 | 'Line Chart', 19 | style: TextStyle( 20 | color: const Color( 21 | 0xff6f6f97, 22 | ), 23 | fontSize: 32, 24 | fontWeight: FontWeight.bold), 25 | ), 26 | ), 27 | ), 28 | const SizedBox( 29 | height: 8, 30 | ), 31 | Padding( 32 | padding: const EdgeInsets.only( 33 | left: 28, 34 | right: 28, 35 | ), 36 | // child: LineChartSample1(), 37 | ), 38 | const SizedBox( 39 | height: 22, 40 | ), 41 | Padding( 42 | padding: const EdgeInsets.only(left: 28.0, right: 28), 43 | // child: LineChartSample2(), 44 | ), 45 | ], 46 | ), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/sample/chart/line_chart/line_chart_page2.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LineChartPage2 extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Container( 7 | color: Colors.white, 8 | child: Center( 9 | child: Padding( 10 | padding: EdgeInsets.symmetric(horizontal: 20), 11 | child: ListView( 12 | children: [ 13 | Text( 14 | 'LineChart', 15 | style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Colors.black), 16 | ), 17 | // LineChartSample3(), 18 | // LineChartSample4(), 19 | // LineChartSample7(), 20 | // LineChartSample5(), 21 | const SizedBox( 22 | height: 22, 23 | ), 24 | Text( 25 | 'Range annotations and dashed path', 26 | style: TextStyle( 27 | color: Colors.black87, 28 | fontSize: 14, 29 | ), 30 | ), 31 | // LineChartSample8(), 32 | ], 33 | ), 34 | ), 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/sample/chart/line_chart/line_chart_page3.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LineChartPage3 extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return SingleChildScrollView( 7 | child: Container( 8 | color: Colors.white, 9 | child: Center( 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 12 | mainAxisSize: MainAxisSize.min, 13 | children: [ 14 | Text( 15 | 'LineChart (reversed)', 16 | style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Colors.black), 17 | ), 18 | const SizedBox( 19 | height: 52, 20 | ), 21 | // LineChartSample6(), 22 | ], 23 | ), 24 | ), 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/sample/chart/line_chart/line_chart_page4.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LineChartPage4 extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Scaffold( 7 | backgroundColor: const Color(0xfff3f3f5), 8 | body: ListView( 9 | padding: const EdgeInsets.all(24), 10 | children: [ 11 | // BarChartSample3(), 12 | const SizedBox( 13 | height: 18, 14 | ), 15 | // BarChartSample4(), 16 | const SizedBox( 17 | height: 18, 18 | ), 19 | // BarChartSample5(), 20 | ], 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/sample/chart/pie_chart/pie_chart_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class PieChartPage extends StatelessWidget { 4 | final Color barColor = Colors.white; 5 | final Color barBackgroundColor = const Color(0xff72d8bf); 6 | final double width = 22; 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Container( 11 | color: const Color(0xffeceaeb), 12 | child: Padding( 13 | padding: const EdgeInsets.all(28.0), 14 | child: ListView( 15 | children: [ 16 | Align( 17 | alignment: Alignment.centerLeft, 18 | child: Padding( 19 | padding: const EdgeInsets.only(left: 8.0), 20 | child: Text( 21 | 'Pie Chart', 22 | style: TextStyle( 23 | color: const Color( 24 | 0xff333333, 25 | ), 26 | fontSize: 32, 27 | fontWeight: FontWeight.bold), 28 | ), 29 | ), 30 | ), 31 | const SizedBox( 32 | height: 8, 33 | ), 34 | // PieChartSample1(), 35 | const SizedBox( 36 | height: 12, 37 | ), 38 | // PieChartSample2(), 39 | ], 40 | ), 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/sample/chart/pie_chart/samples/indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Indicator extends StatelessWidget { 4 | final Color color; 5 | final String text; 6 | final bool isSquare; 7 | final double size; 8 | final Color textColor; 9 | 10 | const Indicator({ 11 | Key? key, 12 | required this.color, 13 | required this.text, 14 | required this.isSquare, 15 | this.size = 16, 16 | this.textColor = const Color(0xff505050), 17 | }) : super(key: key); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Row( 22 | children: [ 23 | Container( 24 | width: size, 25 | height: size, 26 | decoration: BoxDecoration( 27 | shape: isSquare ? BoxShape.rectangle : BoxShape.circle, 28 | color: color, 29 | ), 30 | ), 31 | const SizedBox( 32 | width: 4, 33 | ), 34 | Text( 35 | text, 36 | style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: textColor), 37 | ) 38 | ], 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/sample/chart/scatter_chart/scatter_chart_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'samples/scatter_chart_sample1.dart'; 4 | 5 | class ScatterChartPage extends StatelessWidget { 6 | final Color barColor = Colors.white; 7 | final Color barBackgroundColor = const Color(0xff72d8bf); 8 | final double width = 22; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | backgroundColor: Color(0xffffffff), 14 | body: ListView( 15 | children: [ 16 | Padding( 17 | padding: const EdgeInsets.symmetric( 18 | vertical: 18.0, 19 | horizontal: 22, 20 | ), 21 | child: Text( 22 | 'Scatter Charts', 23 | style: TextStyle( 24 | color: Colors.black, 25 | fontSize: 24, 26 | fontWeight: FontWeight.bold, 27 | ), 28 | ), 29 | ), 30 | const SizedBox( 31 | height: 9, 32 | ), 33 | Padding( 34 | padding: const EdgeInsets.only(left: 18.0, right: 18.0, bottom: 18.0), 35 | child: ScatterChartSample1(), 36 | ), 37 | Padding( 38 | padding: const EdgeInsets.only(left: 18.0, right: 18.0, bottom: 18.0), 39 | // child: ScatterChartSample2(), 40 | ) 41 | ], 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/sample/file/FileMainPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | /// 5 | /// 文件模块主页面 6 | /// 7 | class FileMainPage extends StatefulWidget { 8 | @override 9 | State createState() { 10 | return _FileMainState(); 11 | } 12 | } 13 | 14 | class _FileMainState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar(), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/sample/image/main_image_sort_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// MainImageSortPage 5 | class MainImageSortPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return _MainImageSortState(); 9 | } 10 | } 11 | 12 | /// 13 | /// _MainImageSortState 14 | class _MainImageSortState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: Text("Image"), 20 | ), 21 | body: SingleChildScrollView( 22 | child: Column( 23 | children: [], 24 | ), 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/sample/loading/loading_modal_popup_route.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class LoadingModalPopupRoute extends PopupRoute { 7 | LoadingModalPopupRoute({ 8 | this.barrierColor, 9 | this.barrierLabel, 10 | required this.builder, 11 | bool? semanticsDismissible, 12 | ImageFilter? filter, 13 | RouteSettings? settings, 14 | }) : super( 15 | filter: filter, 16 | settings: settings, 17 | ) { 18 | _semanticsDismissible = semanticsDismissible ?? false; 19 | } 20 | 21 | final WidgetBuilder builder; 22 | late bool _semanticsDismissible; 23 | 24 | @override 25 | final String? barrierLabel; 26 | 27 | @override 28 | final Color? barrierColor; 29 | 30 | @override 31 | bool get barrierDismissible => true; 32 | 33 | @override 34 | bool get semanticsDismissible => _semanticsDismissible ?? false; 35 | 36 | @override 37 | Duration get transitionDuration => Duration(milliseconds: 300); 38 | 39 | late Animation _animation; 40 | 41 | late Tween _offsetTween; 42 | 43 | @override 44 | Animation createAnimation() { 45 | assert(_animation == null); 46 | _animation = CurvedAnimation( 47 | parent: super.createAnimation(), 48 | 49 | // These curves were initially measured from native iOS horizontal page 50 | // route animations and seemed to be a good match here as well. 51 | curve: Curves.linearToEaseOut, 52 | reverseCurve: Curves.linearToEaseOut.flipped, 53 | ); 54 | _offsetTween = Tween( 55 | begin: const Offset(0.0, 1.0), 56 | end: const Offset(0.0, 0.0), 57 | ); 58 | return _animation; 59 | } 60 | 61 | @override 62 | Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { 63 | return CupertinoUserInterfaceLevel( 64 | data: CupertinoUserInterfaceLevelData.elevated, 65 | child: Builder(builder: builder), 66 | ); 67 | } 68 | 69 | @override 70 | Widget buildTransitions(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { 71 | return Align( 72 | alignment: Alignment.center, 73 | child: FractionalTranslation( 74 | translation: _offsetTween.evaluate(_animation), 75 | child: child, 76 | ), 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/sample/loading/main_loading_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | // import 'package:loading/indicator/ball_pulse_indicator.dart'; 3 | // import 'package:loading/loading.dart'; 4 | 5 | /// MainLoadingPage 6 | class MainLoadingPage extends StatefulWidget { 7 | @override 8 | State createState() { 9 | return _MainLoadingState(); 10 | } 11 | } 12 | 13 | /// _MainLoadingState 14 | class _MainLoadingState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar(), 19 | ); 20 | // return Scaffold( 21 | // appBar: AppBar(), 22 | // body: SingleChildScrollView( 23 | // child: Column( 24 | // children: [ 25 | // Container( 26 | // child: Center( 27 | // child: Loading( 28 | // indicator: BallPulseIndicator(), 29 | // size: 100.0, 30 | // color: Colors.pink), 31 | // ), 32 | // ), 33 | // Container( 34 | // child: Center( 35 | // child: Loading( 36 | // indicator: BallPulseIndicator(), 37 | // size: 100.0, 38 | // color: Colors.pink), 39 | // ), 40 | // ), 41 | // ], 42 | // ), 43 | // ), 44 | // ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/sample/notifier/CardInfoPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/sample/notifier/CardModel.dart'; 3 | import 'package:flutter_app_sample/sample/notifier/CardModelByNotifierProvider.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | /// 7 | /// CardInfoPage 8 | /// [ 9 | /// ChangeNotifier 10 | /// ChangeNotifierProvider 11 | /// Consumer 12 | /// ] 13 | /// 14 | class CardInfoPage extends StatefulWidget { 15 | @override 16 | State createState() { 17 | return _CardInfoState(); 18 | } 19 | } 20 | 21 | /// 22 | /// _CardInfoState 23 | class _CardInfoState extends State { 24 | late CardModelBYNotifierProvider _cardModelBYNotifierProvider; 25 | 26 | callback() { 27 | /* 28 | Render 29 | */ 30 | setState(() {}); 31 | } 32 | 33 | @override 34 | void initState() { 35 | super.initState(); 36 | 37 | CardModel.getInstance().addListener(callback); 38 | 39 | _cardModelBYNotifierProvider = CardModelBYNotifierProvider(); 40 | } 41 | 42 | @override 43 | void dispose() { 44 | super.dispose(); 45 | CardModel.getInstance().removeListener(callback); 46 | } 47 | 48 | Widget createWidget() { 49 | return Card( 50 | child: Column( 51 | children: [ 52 | ListTile( 53 | leading: FloatingActionButton( 54 | elevation: 2, 55 | child: Icon(Icons.add), 56 | tooltip: "增加年龄", 57 | onPressed: () { 58 | CardModel.getInstance().age = ++CardModel.getInstance().age; 59 | CardModel.getInstance().notify(); 60 | }, 61 | ), 62 | title: Text("姓名:${CardModel.getInstance().name}"), 63 | subtitle: Text("年龄:${CardModel.getInstance().age}"), 64 | trailing: Text("描述:点击➕号来增加年龄值"), 65 | ), 66 | ChangeNotifierProvider( 67 | create: (BuildContext context) => _cardModelBYNotifierProvider, 68 | child: Consumer( 69 | builder: (context, cart, child) { 70 | return RaisedButton( 71 | onPressed: () { 72 | _cardModelBYNotifierProvider.age = ++_cardModelBYNotifierProvider.age; 73 | 74 | _cardModelBYNotifierProvider.notify(); 75 | }, 76 | child: Text("Total price: ${cart.age}"), 77 | ); 78 | }, 79 | ), 80 | ), 81 | ], 82 | ), 83 | ); 84 | } 85 | 86 | @override 87 | Widget build(BuildContext context) { 88 | return Scaffold( 89 | appBar: AppBar( 90 | title: Text("组件间通信"), 91 | ), 92 | body: createWidget(), 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/sample/notifier/CardMainPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/sample/notifier/CardModel.dart'; 3 | import 'package:airoute/airoute.dart'; 4 | 5 | /// 6 | /// CardMainPage 7 | class CardMainPage extends StatefulWidget { 8 | @override 9 | State createState() { 10 | return _CarMainState(); 11 | } 12 | } 13 | 14 | /// 15 | /// _CarMainState 16 | class _CarMainState extends State { 17 | callback() { 18 | setState(() {}); 19 | } 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | 25 | CardModel.getInstance().addListener(callback); 26 | CardModel.getInstance().age = 0; 27 | CardModel.getInstance().name = "Air"; 28 | CardModel.getInstance().notify(); 29 | } 30 | 31 | @override 32 | void dispose() { 33 | super.dispose(); 34 | CardModel.getInstance().removeListener(callback); 35 | } 36 | 37 | Widget createWidget() { 38 | return Container( 39 | margin: EdgeInsets.all(20), 40 | child: Column( 41 | mainAxisAlignment: MainAxisAlignment.center, 42 | crossAxisAlignment: CrossAxisAlignment.stretch, 43 | children: [ 44 | Container( 45 | margin: EdgeInsets.all(10), 46 | child: Text("通信机制:此页面显示的数据,与跳转后的页面的数据保持一致性!"), 47 | ), 48 | Text( 49 | "这里显示的是消息通信流程中进行更新的数据:\n\nname = ${CardModel.getInstance().name}, age = ${CardModel.getInstance().age}", 50 | textAlign: TextAlign.center, 51 | ), 52 | RaisedButton( 53 | textColor: Colors.white, 54 | color: 55 | ColorTween(begin: Colors.red, end: Colors.blue).transform(0.5), 56 | onPressed: () { 57 | Airoute.pushNamedWithAnimation( 58 | routeName: "/CardInfoPage", 59 | routePageAnimation: AirouteTransition.Slide, 60 | ); 61 | }, 62 | child: Text("跳转页面"), 63 | ), 64 | ], 65 | ), 66 | ); 67 | } 68 | 69 | @override 70 | Widget build(BuildContext context) { 71 | return Scaffold( 72 | appBar: AppBar( 73 | title: Text("消息通信"), 74 | ), 75 | body: createWidget(), 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/sample/notifier/CardModel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CardModel extends ChangeNotifier { 4 | late String _name; 5 | late int _age; 6 | 7 | static CardModel? singletonInstance; 8 | 9 | CardModel._instance(); 10 | 11 | static CardModel getInstance() { 12 | if (singletonInstance == null) { 13 | singletonInstance = CardModel._instance(); 14 | } 15 | return singletonInstance!; 16 | } 17 | 18 | int get age => _age; 19 | 20 | set age(int age) { 21 | this._age = age; 22 | } 23 | 24 | String get name => _name; 25 | 26 | set name(String name) { 27 | this._name = name; 28 | } 29 | 30 | notify() { 31 | notifyListeners(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/sample/notifier/CardModelByNotifierProvider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CardModelBYNotifierProvider extends ChangeNotifier { 4 | String _name = "Air"; 5 | int _age = 0; 6 | 7 | int get age => _age; 8 | set age(int age) { 9 | this._age = age; 10 | } 11 | 12 | String get name => _name; 13 | 14 | set name(String name) { 15 | this._name = name; 16 | } 17 | 18 | notify(){ 19 | notifyListeners(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/sample/overlay/main_overlay_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:airoute/airoute.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// MainOverlayPage 5 | class MainOverlayPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return _MainOverlayState(); 9 | } 10 | } 11 | 12 | /// _MainOverlayState 13 | class _MainOverlayState extends State { 14 | static final Map _overlay = { 15 | //displayName: routeName 16 | "SimpleOverlay": "/SimpleOverlayPage", 17 | }; 18 | 19 | List _overlayDisplayName = _overlay.keys.toList(); 20 | 21 | List _overlayRouteName = _overlay.values.toList(); 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | appBar: AppBar( 27 | title: Text("Overlay"), 28 | ), 29 | body: ListView.builder( 30 | itemCount: _overlayDisplayName.length, 31 | itemBuilder: (context, index) { 32 | String displayName = _overlayDisplayName.elementAt(index); 33 | String routeName = _overlayRouteName.elementAt(index); 34 | return GestureDetector( 35 | onTap: () { 36 | Airoute.pushNamedWithAnimation( 37 | routeName: routeName, 38 | routePageAnimation: AirouteTransition.Slide, 39 | ); 40 | }, 41 | child: Card( 42 | child: ListTile( 43 | leading: Text("$displayName"), 44 | )), 45 | ); 46 | }, 47 | )); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/sample/segment/segment_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// 5 | /// SegmentPage 6 | class SegmentPage extends StatefulWidget { 7 | @override 8 | State createState() { 9 | return _SegmentState(); 10 | } 11 | } 12 | 13 | /// 14 | /// _SegmentState 15 | class _SegmentState extends State { 16 | final Map _segmentChildren = { 17 | 0: Container(padding: EdgeInsets.all(5), child: Text('Child 1')), 18 | 1: Container(padding: EdgeInsets.all(5), child: Text('Child 2')), 19 | 2: Container(padding: EdgeInsets.all(5), child: Text('Child 3')), 20 | 3: Container(padding: EdgeInsets.all(5), child: Text('Child 4')), 21 | 4: Container(padding: EdgeInsets.all(5), child: Text('Child 5')), 22 | 5: Container(padding: EdgeInsets.all(5), child: Text('Child 6')), 23 | }; 24 | int _currentValue = 0; 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | appBar: AppBar( 30 | title: Text("Segment"), 31 | ), 32 | body: Column( 33 | children: [ 34 | CupertinoSegmentedControl( 35 | children: _segmentChildren, 36 | onValueChanged: (int newValue) { 37 | setState(() { 38 | _currentValue = newValue; 39 | }); 40 | }, 41 | padding: EdgeInsets.all(15), 42 | groupValue: _currentValue, 43 | ), 44 | CupertinoSlidingSegmentedControl( 45 | children: _segmentChildren, 46 | onValueChanged: (int? newValue) { 47 | setState(() { 48 | _currentValue = newValue!; 49 | }); 50 | }, 51 | padding: EdgeInsets.all(15), 52 | groupValue: _currentValue, 53 | ), 54 | Spacer(), 55 | ], 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/sample/text/RichTextPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// RichTextPage 5 | class RichTextPage extends StatefulWidget { 6 | final String _richTextMessage = "@Air 你好"; 7 | 8 | @override 9 | State createState() { 10 | return _RichTextState(); 11 | } 12 | } 13 | 14 | /// 15 | /// _RichTextState 16 | class _RichTextState extends State { 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar( 21 | title: Text("RichText"), 22 | ), 23 | body: SingleChildScrollView( 24 | child: Column( 25 | children: [ 26 | Container( 27 | width: 200, 28 | height: 200, 29 | color: Colors.grey, 30 | child: FractionallySizedBox( 31 | widthFactor: 0.8, 32 | heightFactor: 0.5, 33 | alignment: Alignment.centerRight, 34 | child: Container( 35 | decoration: BoxDecoration( 36 | gradient: LinearGradient( 37 | begin: Alignment.topLeft, 38 | end: Alignment.bottomRight, 39 | colors: [], 40 | ), 41 | ), 42 | child: Text.rich( 43 | TextSpan( 44 | text: "Hello richText", 45 | style: _getTextStyleDefaulted(), 46 | children: [ 47 | TextSpan(text: "bold text", style: _getTextStyleDefaulted()), 48 | WidgetSpan(child: Icon(Icons.print)), 49 | ], 50 | ), 51 | ), 52 | ), 53 | ), 54 | ), 55 | ], 56 | ), 57 | ), 58 | ); 59 | } 60 | 61 | /// 62 | /// 获取自定义文本样式 63 | TextStyle _getTextStyleDefaulted() { 64 | return TextStyle( 65 | fontStyle: FontStyle.normal, 66 | color: Colors.white, 67 | fontWeight: FontWeight.normal, 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/sample/text/input_text_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 4 | /// InputTextPage 5 | class InputTextPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return _InputTextState(); 9 | } 10 | } 11 | 12 | /// 13 | /// _InputTextState 14 | class _InputTextState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: Text("InputText"), 20 | ), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/sample/wave/wave_arc_clipper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// WaveArcClipper 4 | /// 5 | /// 圆弧效果的 6 | class WaveArcClipper extends CustomClipper { 7 | late int _count; 8 | late bool _isReverse; 9 | 10 | WaveArcClipper({ 11 | required int waveCount, 12 | bool isReverse = false, 13 | }) { 14 | _count = waveCount; 15 | _isReverse = isReverse; 16 | } 17 | 18 | @override 19 | Path getClip(Size size) { 20 | var path = Path(); 21 | 22 | var _segment = _count * 2; 23 | 24 | double pieceOfWidth = size.width / _segment; 25 | double pieceOfHeight = size.height; 26 | 27 | if (_isReverse) { 28 | path.moveTo(0, 0); 29 | } else { 30 | path.moveTo(0, pieceOfHeight); 31 | } 32 | 33 | for (int i = 0; i < _segment; i++) { 34 | double y = 0.0; 35 | 36 | double left; 37 | double top; 38 | double right; 39 | double bottom; 40 | 41 | late double startAngle; 42 | late double sweepAngle; 43 | 44 | if (_isReverse) { 45 | if (i % 2 == 1) { 46 | y = 0; 47 | left = pieceOfWidth * i; 48 | top = y; 49 | } else { 50 | y = pieceOfHeight; 51 | left = pieceOfWidth * i; 52 | top = y; 53 | } 54 | } else { 55 | if (i % 2 == 1) { 56 | y = pieceOfHeight; 57 | left = pieceOfWidth * i; 58 | top = y; 59 | startAngle = 180; 60 | sweepAngle = -45; 61 | } else { 62 | y = 0; 63 | left = pieceOfWidth * i; 64 | top = y; 65 | startAngle = 180; 66 | sweepAngle = 45; 67 | } 68 | } 69 | Rect rect = Rect.fromLTRB(left, top, left + pieceOfWidth, top + pieceOfHeight); 70 | path.arcTo(rect, startAngle, sweepAngle, false); 71 | } 72 | 73 | path.close(); 74 | return path; 75 | } 76 | 77 | @override 78 | bool shouldReclip(CustomClipper oldClipper) => true; 79 | } 80 | -------------------------------------------------------------------------------- /lib/sample/wave/wave_oval_clipper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// WaveOvalClipper 4 | /// 5 | /// 椭圆效果的 6 | class WaveOvalClipper extends CustomClipper { 7 | late int _count; 8 | late bool _isReverse; 9 | 10 | WaveOvalClipper({ 11 | required int waveCount, 12 | bool isReverse = false, 13 | }) { 14 | _count = waveCount; 15 | _isReverse = isReverse; 16 | } 17 | 18 | @override 19 | Path getClip(Size size) { 20 | var path = Path(); 21 | 22 | var _segment = _count * 2; 23 | 24 | double pieceOfWidth = size.width / _segment; 25 | double pieceOfHeight = size.height; 26 | 27 | if (_isReverse) { 28 | path.moveTo(0, 0); 29 | } else { 30 | path.moveTo(0, pieceOfHeight); 31 | } 32 | 33 | for (int i = 0; i < _segment; i++) { 34 | double y = 0.0; 35 | 36 | double left; 37 | double top; 38 | double right; 39 | double bottom; 40 | 41 | double startAngle; 42 | double sweepAngle; 43 | 44 | if (_isReverse) { 45 | if (i % 2 == 1) { 46 | y = 0; 47 | left = pieceOfWidth * i; 48 | top = y; 49 | } else { 50 | y = pieceOfHeight; 51 | left = pieceOfWidth * i; 52 | top = y; 53 | } 54 | } else { 55 | if (i % 2 == 1) { 56 | y = pieceOfHeight; 57 | left = pieceOfWidth * i; 58 | top = y; 59 | startAngle = 180; 60 | sweepAngle = -45; 61 | } else { 62 | y = 0; 63 | left = pieceOfWidth * i; 64 | top = y; 65 | startAngle = 180; 66 | sweepAngle = 45; 67 | } 68 | } 69 | Rect rect = Rect.fromLTRB(left, top, left + pieceOfWidth, top + pieceOfHeight); 70 | path.addOval(rect); 71 | } 72 | 73 | path.close(); 74 | return path; 75 | } 76 | 77 | @override 78 | bool shouldReclip(CustomClipper oldClipper) => true; 79 | } 80 | -------------------------------------------------------------------------------- /lib/sample/wave/wave_triangle_clipper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// WaveTriangleClipper 4 | /// 5 | /// 三角形效果的 6 | class WaveTriangleClipper extends CustomClipper { 7 | late int _count; 8 | late bool _isReverse; 9 | 10 | WaveTriangleClipper({ 11 | required int waveCount, 12 | bool isReverse = false, 13 | }) { 14 | _count = waveCount; 15 | _isReverse = isReverse; 16 | } 17 | 18 | @override 19 | Path getClip(Size size) { 20 | var path = Path(); 21 | 22 | var _segment = _count * 2; 23 | 24 | double pieceOfWidth = size.width / _segment; 25 | double pieceOfHeight = size.height; 26 | 27 | if (_isReverse) { 28 | path.moveTo(0, 0); 29 | } else { 30 | path.moveTo(0, pieceOfHeight); 31 | } 32 | 33 | for (int i = 0; i < _segment; i++) { 34 | double y = 0.0; 35 | 36 | if (_isReverse) { 37 | if (i % 2 == 1) { 38 | y = 0; 39 | } else { 40 | y = pieceOfHeight; 41 | } 42 | } else { 43 | if (i % 2 == 1) { 44 | y = pieceOfHeight; 45 | } else { 46 | y = 0; 47 | } 48 | } 49 | path.lineTo(pieceOfWidth * (i + 1), y); 50 | } 51 | 52 | path.close(); 53 | return path; 54 | } 55 | 56 | @override 57 | bool shouldReclip(CustomClipper oldClipper) => true; 58 | } 59 | -------------------------------------------------------------------------------- /lib/tv/app_raw_key_board_listener_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:air_design/air_design.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | 5 | import 'key_code.dart'; 6 | 7 | /// 8 | /// AppRawKeyboardListenerWidget 9 | class AppRawKeyboardListenerWidget extends StatefulWidget { 10 | final List focusList; 11 | final int focusIndex; 12 | final Widget child; 13 | final VoidCallback onTelevisionTap; 14 | final VoidCallback onTap; 15 | final ValueChanged? onKey; 16 | AppRawKeyboardListenerWidget.defaultStyle({ 17 | required this.focusList, 18 | required this.focusIndex, 19 | required this.child, 20 | required this.onTelevisionTap, 21 | required this.onTap, 22 | this.onKey, 23 | }) {} 24 | @override 25 | _AppRawKeyboardListenerWidgetState createState() => _AppRawKeyboardListenerWidgetState(); 26 | } 27 | 28 | class _AppRawKeyboardListenerWidgetState extends State { 29 | @override 30 | Widget build(BuildContext context) { 31 | return RawKeyboardListener( 32 | focusNode: widget.focusList[widget.focusIndex], 33 | child: AppCardOutlinedStyleWidget.defaultStyle( 34 | onTap: widget.onTap, 35 | checked: widget.focusList[widget.focusIndex].hasFocus, 36 | child: widget.child, 37 | ), 38 | onKey: (RawKeyEvent event) { 39 | if (event == null) { 40 | return; 41 | } 42 | if (event is RawKeyDownEvent && event.data is RawKeyEventDataAndroid) { 43 | RawKeyDownEvent rawKeyDownEvent = event; 44 | RawKeyEventDataAndroid rawKeyEventDataAndroid = rawKeyDownEvent.data as RawKeyEventDataAndroid; 45 | print("tv launcher sample ${rawKeyEventDataAndroid.keyCode}"); 46 | switch (rawKeyEventDataAndroid.keyCode) { 47 | case KEY_CENTER: 48 | if (widget.onTelevisionTap != null) { 49 | widget.onTelevisionTap(); 50 | } 51 | break; 52 | case KEY_UP: 53 | if (widget.focusIndex == 0) { 54 | } else { 55 | FocusScope.of(context).requestFocus(widget.focusList[widget.focusIndex - 1]); 56 | } 57 | break; 58 | case KEY_DOWN: 59 | if (widget.focusIndex == (widget.focusList.length - 1)) { 60 | } else { 61 | FocusScope.of(context).requestFocus(widget.focusList[widget.focusIndex + 1]); 62 | } 63 | break; 64 | default: 65 | break; 66 | } 67 | //callback 68 | if (widget.onKey != null) { 69 | widget.onKey!(event); 70 | } 71 | } 72 | }, 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/tv/key_code.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// UP 3 | const int KEY_UP = 19; 4 | 5 | /// 6 | /// DOWN 7 | const int KEY_DOWN = 20; 8 | 9 | /// 10 | /// LEFT 11 | const int KEY_LEFT = 21; 12 | 13 | /// 14 | /// RIGHT 15 | const int KEY_RIGHT = 22; 16 | 17 | /// 18 | /// CENTER 19 | const int KEY_CENTER = 23; 20 | -------------------------------------------------------------------------------- /lib/ui/Read: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/lib/ui/Read -------------------------------------------------------------------------------- /lib/ui/common/AppCommonListItem.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | ///AppCommonListItem 4 | ///封装的通用的全局列表的项 5 | ///支持: 6 | ///1、侧滑动 7 | ///2、滑动删除项 8 | ///3、撤销操作2 9 | ///4、项点击事件 10 | ///TODO 进一步完善 11 | class AppCommonListItem extends StatefulWidget { 12 | @override 13 | State createState() { 14 | return _AppCommonListItem(); 15 | } 16 | } 17 | 18 | class _AppCommonListItem extends State { 19 | @override 20 | Widget build(BuildContext context) { 21 | return Text("此功能,待封装!!"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/ui/common/AppCommonTextField.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/ui/style/AppStyle.dart'; 3 | 4 | ///@Air 此类在外部更新状态时无法即使的更新,待修正! 5 | class AppCommonTextField extends StatefulWidget { 6 | TextField textField; 7 | 8 | AppCommonTextField({ 9 | required this.textField, 10 | }); 11 | 12 | @override 13 | _AppCommonTextField createState() { 14 | return _AppCommonTextField(this.textField); 15 | } 16 | } 17 | 18 | class _AppCommonTextField extends State { 19 | final TextField textField; 20 | 21 | _AppCommonTextField(this.textField) {} 22 | 23 | Widget? counter( 24 | BuildContext context, { 25 | required int currentLength, 26 | required int? maxLength, 27 | required bool isFocused, 28 | }) { 29 | return Text( 30 | "${currentLength}/${maxLength}", 31 | ); 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return TextField( 37 | textAlign: textField.textAlign, 38 | maxLength: textField.maxLength, 39 | decoration: InputDecoration( 40 | labelText: textField.decoration!.labelText, 41 | labelStyle: TextStyle( 42 | color: AppStyle.textFieldLabelColor, 43 | ), 44 | hintText: textField.decoration!.hintText, 45 | hintStyle: TextStyle( 46 | color: AppStyle.textFieldHintColor, 47 | ), 48 | errorText: textField.decoration!.errorText, 49 | errorStyle: TextStyle( 50 | color: AppStyle.textFieldErrorColor, 51 | ), 52 | helperText: textField.decoration!.helperText, 53 | helperStyle: TextStyle( 54 | color: AppStyle.textFieldHelperColor, 55 | )), 56 | buildCounter: counter, 57 | onChanged: (String text) { 58 | if (textField.onChanged != null) { 59 | setState(() { 60 | textField.onChanged!(text); 61 | }); 62 | } 63 | }, 64 | onTap: () { 65 | if (textField.onTap != null) { 66 | textField.onTap!(); 67 | } 68 | }, 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/ui/common/AppCommonToolBar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | // ignore: must_be_immutable 4 | class AppCommonToolBar extends AppBar { 5 | AppCommonToolBar({ 6 | Key? key, 7 | Widget? leading, 8 | bool automaticallyImplyLeading = true, 9 | Widget? title, 10 | List? actions, 11 | Widget? flexibleSpace, 12 | PreferredSizeWidget? bottom, 13 | double? elevation, 14 | ShapeBorder? shape, 15 | Color? backgroundColor, 16 | Brightness? brightness, 17 | IconThemeData? iconTheme, 18 | IconThemeData? actionsIconTheme, 19 | TextTheme? textTheme, 20 | bool primary = true, 21 | bool? centerTitle, 22 | double titleSpacing = NavigationToolbar.kMiddleSpacing, 23 | double toolbarOpacity = 1.0, 24 | double bottomOpacity = 1.0, 25 | }) { 26 | if (leading == null) { 27 | leading = GestureDetector( 28 | onTap: () {}, 29 | child: Tooltip( 30 | message: "Back", 31 | child: Icon( 32 | Icons.arrow_back, 33 | color: Colors.white, 34 | ), 35 | ), 36 | ); 37 | } 38 | AppBar( 39 | key: key, 40 | leading: leading, 41 | automaticallyImplyLeading: automaticallyImplyLeading, 42 | title: title, 43 | actions: actions, 44 | flexibleSpace: flexibleSpace, 45 | bottom: bottom, 46 | elevation: elevation, 47 | shape: shape, 48 | backgroundColor: backgroundColor, 49 | brightness: brightness, 50 | iconTheme: iconTheme, 51 | actionsIconTheme: actionsIconTheme, 52 | textTheme: textTheme, 53 | primary: primary, 54 | centerTitle: centerTitle, 55 | titleSpacing: titleSpacing, 56 | toolbarOpacity: toolbarOpacity, 57 | bottomOpacity: bottomOpacity, 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/ui/route/AppRoute.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_sample/component/test/TestPage.dart'; 3 | 4 | class AppRoute { 5 | static var routes = MaterialApp(home: Text(""), routes: { 6 | "TestPage": (BuildContext context) { 7 | return TestPage(); 8 | }, 9 | }); 10 | 11 | /// 12 | static void push(BuildContext context, String routeName) { 13 | Navigator.pushNamed(context, routeName); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/ui/style/AppStyle.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | 4 | class AppStyle{ 5 | 6 | static final Color textFieldLabelColor = Colors.blue; 7 | static final Color textFieldHintColor = Colors.grey; 8 | static final Color textFieldErrorColor = Colors.red; 9 | static final Color textFieldHelperColor = Colors.yellow; 10 | 11 | } -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import ai_barcode 9 | import connectivity_plus_macos 10 | import shared_preferences_macos 11 | import url_launcher_macos 12 | 13 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 14 | AiBarcodePlugin.register(with: registry.registrar(forPlugin: "AiBarcodePlugin")) 15 | ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) 16 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 17 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 18 | } 19 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ai_barcode (0.0.1): 3 | - FlutterMacOS 4 | - connectivity_macos (0.0.1): 5 | - FlutterMacOS 6 | - Reachability 7 | - FlutterMacOS (1.0.0) 8 | - Reachability (3.2) 9 | - shared_preferences_macos (0.0.1): 10 | - FlutterMacOS 11 | - url_launcher_macos (0.0.1): 12 | - FlutterMacOS 13 | 14 | DEPENDENCIES: 15 | - ai_barcode (from `Flutter/ephemeral/.symlinks/plugins/ai_barcode/macos`) 16 | - connectivity_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_macos/macos`) 17 | - FlutterMacOS (from `Flutter/ephemeral`) 18 | - shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`) 19 | - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) 20 | 21 | SPEC REPOS: 22 | trunk: 23 | - Reachability 24 | 25 | EXTERNAL SOURCES: 26 | ai_barcode: 27 | :path: Flutter/ephemeral/.symlinks/plugins/ai_barcode/macos 28 | connectivity_macos: 29 | :path: Flutter/ephemeral/.symlinks/plugins/connectivity_macos/macos 30 | FlutterMacOS: 31 | :path: Flutter/ephemeral 32 | shared_preferences_macos: 33 | :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos 34 | url_launcher_macos: 35 | :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos 36 | 37 | SPEC CHECKSUMS: 38 | ai_barcode: 54be7557c4f79e73988831b5e5b1d334349a14b7 39 | connectivity_macos: 9f30e9d0e67a0bc08a0c563ee82310b51ca6e818 40 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 41 | Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 42 | shared_preferences_macos: 480ce071d0666e37cef23fe6c702293a3d21799e 43 | url_launcher_macos: 45af3d61de06997666568a7149c1be98b41c95d4 44 | 45 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c 46 | 47 | COCOAPODS: 1.10.1 48 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = flutter_app_sample 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.air.flutterAppSample 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.air. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | void main() { 12 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 13 | // Build our app and trigger a frame. 14 | 15 | // Verify that our counter starts at 0. 16 | expect(find.text('0'), findsOneWidget); 17 | expect(find.text('1'), findsNothing); 18 | 19 | // Tap the '+' icon and trigger a frame. 20 | await tester.tap(find.byIcon(Icons.add)); 21 | await tester.pump(); 22 | 23 | // Verify that our counter has incremented. 24 | expect(find.text('0'), findsNothing); 25 | expect(find.text('1'), findsOneWidget); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /web/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/web/avatar.jpg -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | flutter_app_sample 30 | 31 | 32 | 33 | 36 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutter_app_sample", 3 | "short_name": "flutter_app_sample", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | void RegisterPlugins(flutter::PluginRegistry* registry) { 14 | ConnectivityPlusWindowsPluginRegisterWithRegistrar( 15 | registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); 16 | PermissionHandlerWindowsPluginRegisterWithRegistrar( 17 | registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); 18 | UrlLauncherWindowsRegisterWithRegistrar( 19 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 20 | } 21 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | connectivity_plus_windows 7 | permission_handler_windows 8 | url_launcher_windows 9 | ) 10 | 11 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 12 | ) 13 | 14 | set(PLUGIN_BUNDLED_LIBRARIES) 15 | 16 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 17 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 18 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 21 | endforeach(plugin) 22 | 23 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 24 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 26 | endforeach(ffi_plugin) 27 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(runner LANGUAGES CXX) 3 | 4 | add_executable(${BINARY_NAME} WIN32 5 | "flutter_window.cpp" 6 | "main.cpp" 7 | "run_loop.cpp" 8 | "utils.cpp" 9 | "win32_window.cpp" 10 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 11 | "Runner.rc" 12 | "runner.exe.manifest" 13 | ) 14 | apply_standard_settings(${BINARY_NAME}) 15 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 16 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 17 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 18 | add_dependencies(${BINARY_NAME} flutter_assemble) 19 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(RunLoop* run_loop, 8 | const flutter::DartProject& project) 9 | : run_loop_(run_loop), project_(project) {} 10 | 11 | FlutterWindow::~FlutterWindow() {} 12 | 13 | bool FlutterWindow::OnCreate() { 14 | if (!Win32Window::OnCreate()) { 15 | return false; 16 | } 17 | 18 | RECT frame = GetClientArea(); 19 | 20 | // The size here must match the window dimensions to avoid unnecessary surface 21 | // creation / destruction in the startup path. 22 | flutter_controller_ = std::make_unique( 23 | frame.right - frame.left, frame.bottom - frame.top, project_); 24 | // Ensure that basic setup of the controller was successful. 25 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 26 | return false; 27 | } 28 | RegisterPlugins(flutter_controller_->engine()); 29 | run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); 30 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 31 | return true; 32 | } 33 | 34 | void FlutterWindow::OnDestroy() { 35 | if (flutter_controller_) { 36 | run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); 37 | flutter_controller_ = nullptr; 38 | } 39 | 40 | Win32Window::OnDestroy(); 41 | } 42 | 43 | LRESULT 44 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 45 | WPARAM const wparam, 46 | LPARAM const lparam) noexcept { 47 | // Give Flutter, including plugins, an opportunity to handle window messages. 48 | if (flutter_controller_) { 49 | std::optional result = 50 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 51 | lparam); 52 | if (result) { 53 | return *result; 54 | } 55 | } 56 | 57 | switch (message) { 58 | case WM_FONTCHANGE: 59 | flutter_controller_->engine()->ReloadSystemFonts(); 60 | break; 61 | } 62 | 63 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 64 | } 65 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "run_loop.h" 10 | #include "win32_window.h" 11 | 12 | // A window that does nothing but host a Flutter view. 13 | class FlutterWindow : public Win32Window { 14 | public: 15 | // Creates a new FlutterWindow driven by the |run_loop|, hosting a 16 | // Flutter view running |project|. 17 | explicit FlutterWindow(RunLoop* run_loop, 18 | const flutter::DartProject& project); 19 | virtual ~FlutterWindow(); 20 | 21 | protected: 22 | // Win32Window: 23 | bool OnCreate() override; 24 | void OnDestroy() override; 25 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 26 | LPARAM const lparam) noexcept override; 27 | 28 | private: 29 | // The run loop driving events for this window. 30 | RunLoop* run_loop_; 31 | 32 | // The project to run. 33 | flutter::DartProject project_; 34 | 35 | // The Flutter instance hosted by this window. 36 | std::unique_ptr flutter_controller_; 37 | }; 38 | 39 | #endif // RUNNER_FLUTTER_WINDOW_H_ 40 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "run_loop.h" 7 | #include "utils.h" 8 | 9 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 10 | _In_ wchar_t *command_line, _In_ int show_command) { 11 | // Attach to console when present (e.g., 'flutter run') or create a 12 | // new console when running with a debugger. 13 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 14 | CreateAndAttachConsole(); 15 | } 16 | 17 | // Initialize COM, so that it is available for use in the library and/or 18 | // plugins. 19 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 20 | 21 | RunLoop run_loop; 22 | 23 | flutter::DartProject project(L"data"); 24 | 25 | std::vector command_line_arguments = 26 | GetCommandLineArguments(); 27 | 28 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 29 | 30 | FlutterWindow window(&run_loop, project); 31 | Win32Window::Point origin(10, 10); 32 | Win32Window::Size size(1280, 720); 33 | if (!window.CreateAndShow(L"flutter_app_sample", origin, size)) { 34 | return EXIT_FAILURE; 35 | } 36 | window.SetQuitOnClose(true); 37 | 38 | run_loop.Run(); 39 | 40 | ::CoUninitialize(); 41 | return EXIT_SUCCESS; 42 | } 43 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdliuw/flutter_app_sample/6c79f03fe083af02775c8645c6f323ed385f38d8/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /windows/runner/run_loop.cpp: -------------------------------------------------------------------------------- 1 | #include "run_loop.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | RunLoop::RunLoop() {} 8 | 9 | RunLoop::~RunLoop() {} 10 | 11 | void RunLoop::Run() { 12 | bool keep_running = true; 13 | TimePoint next_flutter_event_time = TimePoint::clock::now(); 14 | while (keep_running) { 15 | std::chrono::nanoseconds wait_duration = 16 | std::max(std::chrono::nanoseconds(0), 17 | next_flutter_event_time - TimePoint::clock::now()); 18 | ::MsgWaitForMultipleObjects( 19 | 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), 20 | QS_ALLINPUT); 21 | bool processed_events = false; 22 | MSG message; 23 | // All pending Windows messages must be processed; MsgWaitForMultipleObjects 24 | // won't return again for items left in the queue after PeekMessage. 25 | while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { 26 | processed_events = true; 27 | if (message.message == WM_QUIT) { 28 | keep_running = false; 29 | break; 30 | } 31 | ::TranslateMessage(&message); 32 | ::DispatchMessage(&message); 33 | // Allow Flutter to process messages each time a Windows message is 34 | // processed, to prevent starvation. 35 | next_flutter_event_time = 36 | std::min(next_flutter_event_time, ProcessFlutterMessages()); 37 | } 38 | // If the PeekMessage loop didn't run, process Flutter messages. 39 | if (!processed_events) { 40 | next_flutter_event_time = 41 | std::min(next_flutter_event_time, ProcessFlutterMessages()); 42 | } 43 | } 44 | } 45 | 46 | void RunLoop::RegisterFlutterInstance( 47 | flutter::FlutterEngine* flutter_instance) { 48 | flutter_instances_.insert(flutter_instance); 49 | } 50 | 51 | void RunLoop::UnregisterFlutterInstance( 52 | flutter::FlutterEngine* flutter_instance) { 53 | flutter_instances_.erase(flutter_instance); 54 | } 55 | 56 | RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { 57 | TimePoint next_event_time = TimePoint::max(); 58 | for (auto instance : flutter_instances_) { 59 | std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); 60 | if (wait_duration != std::chrono::nanoseconds::max()) { 61 | next_event_time = 62 | std::min(next_event_time, TimePoint::clock::now() + wait_duration); 63 | } 64 | } 65 | return next_event_time; 66 | } 67 | -------------------------------------------------------------------------------- /windows/runner/run_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_RUN_LOOP_H_ 2 | #define RUNNER_RUN_LOOP_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | // A runloop that will service events for Flutter instances as well 10 | // as native messages. 11 | class RunLoop { 12 | public: 13 | RunLoop(); 14 | ~RunLoop(); 15 | 16 | // Prevent copying 17 | RunLoop(RunLoop const&) = delete; 18 | RunLoop& operator=(RunLoop const&) = delete; 19 | 20 | // Runs the run loop until the application quits. 21 | void Run(); 22 | 23 | // Registers the given Flutter instance for event servicing. 24 | void RegisterFlutterInstance( 25 | flutter::FlutterEngine* flutter_instance); 26 | 27 | // Unregisters the given Flutter instance from event servicing. 28 | void UnregisterFlutterInstance( 29 | flutter::FlutterEngine* flutter_instance); 30 | 31 | private: 32 | using TimePoint = std::chrono::steady_clock::time_point; 33 | 34 | // Processes all currently pending messages for registered Flutter instances. 35 | TimePoint ProcessFlutterMessages(); 36 | 37 | std::set flutter_instances_; 38 | }; 39 | 40 | #endif // RUNNER_RUN_LOOP_H_ 41 | -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | if (target_length == 0) { 52 | return std::string(); 53 | } 54 | std::string utf8_string; 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | --------------------------------------------------------------------------------