├── .gitignore
├── .metadata
├── README.md
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── rjx
│ │ │ │ └── xiechengwang_app
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ ├── common_ctrip_slashscreen.png
│ │ │ └── launch_background.xml
│ │ │ ├── layout
│ │ │ └── launch_screen.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── common_ic_launcher.png
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── asr_plugin
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── libs
│ │ └── bdasr_V3_20191210_81acdf5.jar
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── rjx
│ │ │ └── asr_plugin
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ │ ├── README.txt
│ │ │ ├── WakeUp.bin
│ │ │ └── baidu_speech_grammar.bsg
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── rjx
│ │ │ │ └── asr_plugin
│ │ │ │ ├── AsrManager.java
│ │ │ │ ├── AsrPlugin.java
│ │ │ │ ├── OnAsrListener.java
│ │ │ │ ├── RecogEventAdapter.java
│ │ │ │ ├── RecogResult.java
│ │ │ │ └── ResultStateful.java
│ │ ├── jniLibs
│ │ │ ├── arm64-v8a
│ │ │ │ ├── libBaiduSpeechSDK.so
│ │ │ │ └── libvad.dnn.so
│ │ │ ├── x86
│ │ │ │ ├── libBaiduSpeechSDK.so
│ │ │ │ └── libvad.dnn.so
│ │ │ └── x86_64
│ │ │ │ ├── libBaiduSpeechSDK.so
│ │ │ │ └── libvad.dnn.so
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── rjx
│ │ └── asr_plugin
│ │ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── key.properties
├── proguard-rules.pro
├── settings.gradle
└── xiecheng.jks
├── app-release.apk
├── images
├── type_channelgroup.png
├── type_channellgs.png
├── type_channelplane.png
├── type_channeltrain.png
├── type_cruise.png
├── type_district.png
├── type_food.png
├── type_hotel.png
├── type_huodong.png
├── type_shop.png
├── type_sight.png
├── type_ticket.png
└── type_travelgroup.png
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ └── contents.xcworkspacedata
└── 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
├── dao
│ ├── home_dao.dart
│ ├── search_dao.dart
│ ├── travel_dao.dart
│ └── travel_tab_dao.dart
├── main.dart
├── model
│ ├── common_model.dart
│ ├── config_mdoel.dart
│ ├── grid_nav_model.dart
│ ├── home_model.dart
│ ├── sales_box_model.dart
│ ├── search_model.dart
│ ├── travel_model.dart
│ └── travel_tab_model.dart
├── navigator
│ └── tab_navigator.dart
├── pages
│ ├── home_page.dart
│ ├── my_page.dart
│ ├── search_page.dart
│ ├── speak_page.dart
│ ├── travel_page.dart
│ └── travel_tab_page.dart
├── plugin
│ └── asr_manager.dart
├── util
│ └── navigator_util.dart
└── widget
│ ├── grid_nav.dart
│ ├── loading_container.dart
│ ├── local_nav.dart
│ ├── sales_box.dart
│ ├── search_bar.dart
│ ├── sub_nav.dart
│ └── webview.dart
├── pubspec.lock
├── pubspec.yaml
├── screenshot
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
├── 7.png
├── alt_1.PNG
├── alt_2.PNG
├── alt_3.PNG
├── alt_4.PNG
├── alt_5.PNG
├── alt_6.PNG
├── alt_7.PNG
└── download.png
└── test
└── widget_test.dart
/.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 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 |
32 | # Web related
33 | lib/generated_plugin_registrant.dart
34 |
35 | # Exceptions to above rules.
36 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
37 |
--------------------------------------------------------------------------------
/.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: 056f7244ef02947c37b2369fe542ea87af6e1173
8 | channel: master
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # xiechengwang_app
2 |
3 | > 一款仿携程旅行 Flutter App [速学CrazyCodeBoy](https://coding.imooc.com/class/321.html)
4 |
5 | [**下载** ](https://github.com/raojianxiong/xiechengwang_app/blob/master/app-release.apk) 点击下载应用
6 |
7 | 扫描下载
8 |
9 | 
10 |
11 | ## 目录
12 |
13 | * 主要页面,包括首页、搜索、旅拍和我的四个主页面
14 |
15 | * 依赖库
16 |
17 | * 实际效果
18 |
19 |
20 | ### 主要页面
21 |
22 | * 整体框架采用PageView + BottomNavigationBar ,每个页面的状态保存采用AutomaticKeepAliveClientMixin
23 |
24 | * 首页
25 |
26 | * 全面屏适配,体现在顶部搜索框距离状态栏的距离,项目内笔者采用的是
27 |
28 | ```
29 | MediaQueryData.fromWindow(window).padding.top
30 | ```
31 |
32 | 得到状态栏高度进行适配,当然也可以使用SafeArea来包裹页面。(使用了Scaffold的appbar与bottomNavigationBar是不需要适配的,因为Scaffold框架会自动帮我们完成这些适配工作)
33 |
34 | * 轮播图主要采用的是Swiper控件
35 |
36 | * 列表采用ListView控件,如果数据过多,需要上拉加载建议使用ListView的Builder方法进行服用View
37 |
38 | * 主页整体布局采用了Stack + MediaQuery.removePadding + RefreshIndicator + appBar
39 |
40 | * 通过对Container进行alpha设置实现appBar的颜色渐变
41 |
42 | * 搜索
43 |
44 | * 语音识别采用百度API,native接入百度语音识别API,这里需要注意build.gradle的设置,由于笔者是通过新建android模块,所以需要仿照主app的build.gradle对fltter引入,才能导入MethodChannel相关类。此处涉及Flutter与native通信,两端方法名需要一致。
45 | * 语音识别后自动跳转就行搜索,利用ListView显示数据,用到FractionallySizedBox控件撑满屏幕宽度,利用Expand设置权重,个人感觉Expand等价于LinearLayout,flex属性和weight属性类似
46 |
47 | * 旅拍
48 |
49 | * TabBar + Flexible+ TabBarView
50 | * RefreshIndicator + StaggeredGridView + Stack + Card + PhysicalModel 实现下拉刷新 上拉加载
51 | * 文字固定宽度 LimitedBox
52 | * 圆形图片使用 PhysicalModel 圆角设置为控件长/宽一半
53 |
54 | * 我的
55 |
56 | * WebView
57 |
58 | * 网页加载
59 |
60 | * 所有点击功能采用GestureDetector控件实现,网页使用WebView(利用FlutterWebviewPlugin控件自定义)控件加载
61 | * 当然也可以利用webview_flutter插件替代上述自定义WebView
62 |
63 | * 网络
64 |
65 | * 采用Http get和post请求,json解析
66 |
67 | * 接口在项目内
68 |
69 |
70 | ### 依赖库
71 |
72 | * flutter_swiper: ^1.1.4
73 | * http: ^0.12.0+4
74 | * flutter_webview_plugin: ^0.3.10+1
75 | * flutter_staggered_grid_view: ^0.3.0
76 | * flutter_splash_screen: ^0.1.0
77 | * [Flutter插件开发](https://flutterchina.club/developing-packages/) [Flutter插件库](https://pub.flutter-io.cn/packages/)
78 |
79 |
80 |
81 | ### 实际效果
82 |
83 | 
84 |
85 | 
86 |
87 | 
88 |
89 | 
90 |
91 | 
92 |
93 | 
94 |
95 | 
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/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 | def keystoreProperties = new Properties()
29 | def keystorePropertiesFile = rootProject.file('key.properties')
30 | if (keystorePropertiesFile.exists()) {
31 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
32 | }
33 |
34 | android {
35 | compileSdkVersion 28
36 |
37 | sourceSets {
38 | main.java.srcDirs += 'src/main/kotlin'
39 | }
40 |
41 | lintOptions {
42 | disable 'InvalidPackage'
43 | }
44 |
45 | defaultConfig {
46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
47 | applicationId "com.rjx.xiechengwang_app"
48 | minSdkVersion 16
49 | targetSdkVersion 28
50 | versionCode flutterVersionCode.toInteger()
51 | versionName flutterVersionName
52 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
53 | ndk {
54 | abiFilters "arm64-v8a", "x86_64", "x86" //只打包flutter所支持的架构
55 | }
56 | }
57 | signingConfigs {
58 | release {
59 | keyAlias keystoreProperties['keyAlias']
60 | keyPassword keystoreProperties['keyPassword']
61 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
62 | storePassword keystoreProperties['storePassword']
63 | }
64 | }
65 | buildTypes {
66 | release {
67 | // TODO: Add your own signing config for the release build.
68 | // Signing with the debug keys for now, so `flutter run --release` works.
69 | signingConfig signingConfigs.release
70 | minifyEnabled true
71 |
72 | }
73 | }
74 | //app 与 asr_plugin 都依赖于 libflutter.so merge时会冲突
75 | packagingOptions {
76 |
77 | pickFirst 'lib/x86-64/libflutter.so'
78 | pickFirst 'lib/x86/libflutter.so'
79 | pickFirst 'lib/arm64-v8a/libflutter.so'
80 | pickFirst 'lib/armeabi-v7a/libapp.so'
81 | pickFirst 'lib/arm64-v8a/libapp.so'
82 | }
83 |
84 | }
85 | flutter {
86 | source '../..'
87 | }
88 |
89 | dependencies {
90 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
91 | testImplementation 'junit:junit:4.12'
92 | androidTestImplementation 'androidx.test:runner:1.1.1'
93 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
94 | implementation project(':asr_plugin')
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
15 |
22 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/rjx/xiechengwang_app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.rjx.xiechengwang_app
2 |
3 | import android.os.Bundle
4 | import com.rjx.asr_plugin.AsrPlugin
5 |
6 | import io.flutter.app.FlutterActivity
7 | import io.flutter.plugins.GeneratedPluginRegistrant
8 | import org.devio.flutter.splashscreen.SplashScreen
9 |
10 | class MainActivity : FlutterActivity() {
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | SplashScreen.show(this,true)
13 | super.onCreate(savedInstanceState)
14 | GeneratedPluginRegistrant.registerWith(this)
15 | registerSelfPlugin()
16 | }
17 |
18 | private fun registerSelfPlugin() {
19 | AsrPlugin.registerWith(registrarFor("com.rjx.asr_plugin.AsrPlugin"))
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/common_ctrip_slashscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/app/src/main/res/drawable/common_ctrip_slashscreen.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/layout/launch_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/common_ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/app/src/main/res/mipmap-hdpi/common_ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #000000
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/asr_plugin/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/android/asr_plugin/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | def localProperties = new Properties()
4 | def localPropertiesFile = rootProject.file('local.properties')
5 | if (localPropertiesFile.exists()) {
6 | localPropertiesFile.withReader('UTF-8') { reader ->
7 | localProperties.load(reader)
8 | }
9 | }
10 | def flutterRoot = localProperties.getProperty('flutter.sdk')
11 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
12 |
13 |
14 | android {
15 | compileSdkVersion 28
16 | // buildToolsVersion "29.0.2"
17 |
18 |
19 | defaultConfig {
20 | minSdkVersion 16
21 | targetSdkVersion 28
22 | versionCode 1
23 | versionName "1.0"
24 |
25 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
26 | consumerProguardFiles 'consumer-rules.pro'
27 | }
28 |
29 | buildTypes {
30 | release {
31 | minifyEnabled false
32 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
33 | }
34 | }
35 | packagingOptions{
36 | doNotStrip "*/*/libvad.dnn.so"
37 |
38 | }
39 |
40 | }
41 | flutter {
42 | source '../..'
43 | }
44 | dependencies {
45 | implementation fileTree(dir: 'libs', include: ['*.jar'])
46 |
47 | implementation 'androidx.appcompat:appcompat:1.0.2'
48 | testImplementation 'junit:junit:4.12'
49 | androidTestImplementation 'androidx.test.ext:junit:1.1.0'
50 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
51 | }
52 |
--------------------------------------------------------------------------------
/android/asr_plugin/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/consumer-rules.pro
--------------------------------------------------------------------------------
/android/asr_plugin/libs/bdasr_V3_20191210_81acdf5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/libs/bdasr_V3_20191210_81acdf5.jar
--------------------------------------------------------------------------------
/android/asr_plugin/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 | -keep class com.baidu.speech.**{*;}
23 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/androidTest/java/com/rjx/asr_plugin/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.rjx.asr_plugin;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("com.rjx.asr_plugin.test", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
21 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/assets/README.txt:
--------------------------------------------------------------------------------
1 | 百度语音识别SDK在demo程序中assets目录的文件解释说明:
2 | WakeUp.bin 唤醒功能的唤醒词配置文件, 需要在百度语音开发平台中定义和导出 http://speech.baidu.com/wake
3 | baidu_speech_grammar.bsg 自定义语义以及离线命令词识别共用的语法文件, 需要在百度语音开发平台中定义和导出 http://speech.baidu.com/asr
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/assets/WakeUp.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/src/main/assets/WakeUp.bin
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/assets/baidu_speech_grammar.bsg:
--------------------------------------------------------------------------------
1 | %7B%0A%20%20%20%20%22version%22%3A%20%220.1%22%2C%0A%20%20%20%20%22slots%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%22name%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E5%BC%A0%E4%B8%89%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E6%9D%8E%E5%9B%9B%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E7%8E%8B%E4%BA%94%22%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22appname%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E5%BE%AE%E4%BF%A1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E7%9F%AD%E4%BF%A1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E8%AE%A1%E7%AE%97%E5%99%A8%22%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22msgbody%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22.%2B%22%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22rules%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%22telephone.call%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%89%93%E7%BB%99%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%89%93%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%91%BC%E5%8F%AB%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%91%BC%E5%8F%AB(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E7%BB%99%3Cname%3E%E6%89%93%E7%94%B5%E8%AF%9D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%E6%89%93%E7%94%B5%E8%AF%9D%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22contacts.view%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%9F%A5%E7%9C%8B%3Cname%3E%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%9F%A5%E7%9C%8B(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%9F%A5%E7%9C%8B%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%9F%A5%E7%9C%8B(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22contacts.create%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22contacts.remove%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%88%A0%E9%99%A4%3Cname%3E%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%88%A0%E9%99%A4(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22message.view%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%9F%A5%E7%9C%8B%E6%9C%AA%E8%AF%BB%E7%9F%AD%E4%BF%A1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%9F%A5%E7%9C%8B%E6%9C%AA%E8%AF%BB%E7%9F%AD%E4%BF%A1%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22message.send%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%E5%86%85%E5%AE%B9%E6%98%AF%3Cmsgbody%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%E5%86%85%E5%AE%B9%E6%98%AF(.%2B)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22msgbody%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22app.open%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%89%93%E5%BC%80%3Cappname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%89%93%E5%BC%80(%E5%BE%AE%E4%BF%A1%7C%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%E7%9F%AD%E4%BF%A1%7C%E8%AE%A1%E7%AE%97%E5%99%A8)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22appname%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%90%AF%E5%8A%A8%3Cappname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%90%AF%E5%8A%A8(%E5%BE%AE%E4%BF%A1%7C%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%E7%9F%AD%E4%BF%A1%7C%E8%AE%A1%E7%AE%97%E5%99%A8)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22appname%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22app.search%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%90%9C%E7%B4%A2%3Cappname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%90%9C%E7%B4%A2(%E5%BE%AE%E4%BF%A1%7C%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%E7%9F%AD%E4%BF%A1%7C%E8%AE%A1%E7%AE%97%E5%99%A8)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22appname%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22app.download%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E4%B8%8B%E8%BD%BD%3Cappname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E4%B8%8B%E8%BD%BD(%E5%BE%AE%E4%BF%A1%7C%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%E7%9F%AD%E4%BF%A1%7C%E8%AE%A1%E7%AE%97%E5%99%A8)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22appname%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22grammar%22%3A%20%22%3Cname%3E%20%3D%20%E5%BC%A0%E4%B8%89%7C%20%5Cn%E6%9D%8E%E5%9B%9B%7C%20%5Cn%E7%8E%8B%E4%BA%94%3B%5Cn%3Cappname%3E%20%3D%20%E5%BE%AE%E4%BF%A1%7C%20%5Cn%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%20%5Cn%E7%9F%AD%E4%BF%A1%7C%20%5Cn%E8%AE%A1%E7%AE%97%E5%99%A8%3B%5Cn%3Cmsgbody%3E%20%3D%20%E8%AF%8D%E6%9D%A1%E9%BB%98%E8%AE%A4%E5%80%BC%3B%5Cn%3Cauto_create_node%3E%20%3D%20%E6%9F%A5%E7%9C%8B%E6%9C%AA%E8%AF%BB%E7%9F%AD%E4%BF%A1%3B%5Cn%3C_wakeup%3E%20%3D%20%E5%94%A4%E9%86%92%E8%AF%8D%E5%8D%A0%E4%BD%8D%E7%AC%A6%3B%5Cn%5Cn%5Cn_SCENE_ID_%200%5Cn%5Cn(%20%3Cauto_create_node%3E%20)%5Cn%5Cn(%20%3C_wakeup%3E%3Cauto_create_node%3E%20)%5Cn%5Cn(%20%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99%3Cname%3E%20)%5Cn(%20%E6%89%93%E7%BB%99%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%89%93%E7%BB%99%3Cname%3E%20)%5Cn(%20%E5%91%BC%E5%8F%AB%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E5%91%BC%E5%8F%AB%3Cname%3E%20)%5Cn(%20%E7%BB%99%3Cname%3E%E6%89%93%E7%94%B5%E8%AF%9D%20)%5Cn(%20%3C_wakeup%3E%E7%BB%99%3Cname%3E%E6%89%93%E7%94%B5%E8%AF%9D%20)%5Cn(%20%E6%9F%A5%E7%9C%8B%3Cname%3E%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%20)%5Cn(%20%3C_wakeup%3E%E6%9F%A5%E7%9C%8B%3Cname%3E%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%20)%5Cn(%20%E6%9F%A5%E7%9C%8B%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%9F%A5%E7%9C%8B%3Cname%3E%20)%5Cn(%20%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA%3Cname%3E%20)%5Cn(%20%E5%88%A0%E9%99%A4%3Cname%3E%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%20)%5Cn(%20%3C_wakeup%3E%E5%88%A0%E9%99%A4%3Cname%3E%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%20)%5Cn(%20%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%20)%5Cn(%20%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%E5%86%85%E5%AE%B9%E6%98%AF%3Cmsgbody%3E%20)%5Cn(%20%3C_wakeup%3E%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%E5%86%85%E5%AE%B9%E6%98%AF%3Cmsgbody%3E%20)%5Cn(%20%E6%89%93%E5%BC%80%3Cappname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%89%93%E5%BC%80%3Cappname%3E%20)%5Cn(%20%E5%90%AF%E5%8A%A8%3Cappname%3E%20)%5Cn(%20%3C_wakeup%3E%E5%90%AF%E5%8A%A8%3Cappname%3E%20)%5Cn(%20%E6%90%9C%E7%B4%A2%3Cappname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%90%9C%E7%B4%A2%3Cappname%3E%20)%5Cn(%20%E4%B8%8B%E8%BD%BD%3Cappname%3E%20)%5Cn(%20%3C_wakeup%3E%E4%B8%8B%E8%BD%BD%3Cappname%3E%20)%5Cn%22%2C%0A%20%20%20%20%22origin_slots%22%3A%20%22name%20%3D%20%E5%BC%A0%E4%B8%89%2C%20%E6%9D%8E%E5%9B%9B%2C%20%E7%8E%8B%E4%BA%94%5Cnappname%20%3D%20%E5%BE%AE%E4%BF%A1%2C%20%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%2C%20%E7%9F%AD%E4%BF%A1%2C%20%E8%AE%A1%E7%AE%97%E5%99%A8%5Cnmsgbody%20%3D%20*%22%2C%0A%20%20%20%20%22origin_rules%22%3A%20%22telephone.call%20%20%20%20%20%3D%20%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99%3Cname%3E%2C%20%E6%89%93%E7%BB%99%3Cname%3E%2C%20%E5%91%BC%E5%8F%AB%3Cname%3E%2C%E7%BB%99%3Cname%3E%E6%89%93%E7%94%B5%E8%AF%9D%5Cncontacts.view%20%20%20%20%20%3D%20%E6%9F%A5%E7%9C%8B%3Cname%3E%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%2C%20%E6%9F%A5%E7%9C%8B%3Cname%3E%5Cncontacts.create%20%20%3D%20%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA%3Cname%3E%5Cncontacts.remove%3D%20%E5%88%A0%E9%99%A4%3Cname%3E%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%5Cnmessage.view%20%20%20%20%20%3D%20%E6%9F%A5%E7%9C%8B%E6%9C%AA%E8%AF%BB%E7%9F%AD%E4%BF%A1%5Cnmessage.send%20%20%20%20%3D%20%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%2C%20%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%E5%86%85%E5%AE%B9%E6%98%AF%3Cmsgbody%3E%5Cnapp.open%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%E6%89%93%E5%BC%80%3Cappname%3E%2C%20%E5%90%AF%E5%8A%A8%3Cappname%3E%5Cnapp.search%20%20%20%20%20%20%20%20%20%3D%20%E6%90%9C%E7%B4%A2%3Cappname%3E%5Cnapp.download%20%20%20%20%3D%20%E4%B8%8B%E8%BD%BD%3Cappname%3E%22%0A%7D
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/java/com/rjx/asr_plugin/AsrManager.java:
--------------------------------------------------------------------------------
1 | package com.rjx.asr_plugin;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | import com.baidu.speech.EventListener;
7 | import com.baidu.speech.EventManager;
8 | import com.baidu.speech.EventManagerFactory;
9 | import com.baidu.speech.asr.SpeechConstant;
10 | import org.json.JSONObject;
11 |
12 | import java.util.Map;
13 |
14 | /**
15 | * Created by fujiayi on 2017/6/13.
16 | * EventManager内的方法如send 都可以在主线程中进行,SDK中做过处理
17 | */
18 |
19 | public class AsrManager {
20 | /**
21 | * SDK 内部核心 EventManager 类
22 | */
23 | private EventManager asr;
24 |
25 | // SDK 内部核心 事件回调类, 用于开发者写自己的识别回调逻辑
26 | private EventListener eventListener;
27 |
28 | // 是否加载离线资源
29 | private static boolean isOfflineEngineLoaded = false;
30 |
31 | // 未release前,只能new一个
32 | private static volatile boolean isInited = false;
33 |
34 | private static final String TAG = "AsrManager";
35 |
36 | /**
37 | * 初始化
38 | *
39 | * @param context
40 | * @param recogListener 将EventListener结果做解析的DEMO回调。使用RecogEventAdapter 适配EventListener
41 | */
42 | public AsrManager(Context context, OnAsrListener recogListener) {
43 | this(context, new RecogEventAdapter(recogListener));
44 | }
45 |
46 | /**
47 | * 初始化 提供 EventManagerFactory需要的Context和EventListener
48 | *
49 | * @param context
50 | * @param eventListener 识别状态和结果回调
51 | */
52 | public AsrManager(Context context, EventListener eventListener) {
53 | if (isInited) {
54 | Log.e(TAG, "还未调用release(),请勿新建一个新类");
55 | throw new RuntimeException("还未调用release(),请勿新建一个新类");
56 | }
57 | isInited = true;
58 | this.eventListener = eventListener;
59 | // SDK集成步骤 初始化asr的EventManager示例,多次得到的类,只能选一个使用
60 | asr = EventManagerFactory.create(context, "asr");
61 | // SDK集成步骤 设置回调event, 识别引擎会回调这个类告知重要状态和识别结果
62 | asr.registerListener(eventListener);
63 | }
64 |
65 |
66 | /**
67 | * 离线命令词,在线不需要调用
68 | *
69 | * @param params 离线命令词加载参数,见文档“ASR_KWS_LOAD_ENGINE 输入事件参数”
70 | */
71 | public void loadOfflineEngine(Map params) {
72 | String json = new JSONObject(params).toString();
73 | Log.i(TAG + ".Debug", "离线命令词初始化参数(反馈请带上此行日志):" + json);
74 | // SDK集成步骤(可选)加载离线命令词(离线时使用)
75 | asr.send(SpeechConstant.ASR_KWS_LOAD_ENGINE, json, null, 0, 0);
76 | isOfflineEngineLoaded = true;
77 | }
78 |
79 | /**
80 | * @param params
81 | */
82 | public void start(Map params) {
83 | if (!isInited) {
84 | throw new RuntimeException("release() was called");
85 | }
86 | // SDK集成步骤 拼接识别参数
87 | String json = new JSONObject(params).toString();
88 | Log.i(TAG + ".Debug", "识别参数(反馈请带上此行日志)" + json);
89 | asr.send(SpeechConstant.ASR_START, json, null, 0, 0);
90 | }
91 |
92 |
93 | /**
94 | * 提前结束录音等待识别结果。
95 | */
96 | public void stop() {
97 | Log.i(TAG, "停止录音");
98 | // SDK 集成步骤(可选)停止录音
99 | if (!isInited) {
100 | throw new RuntimeException("release() was called");
101 | }
102 | asr.send(SpeechConstant.ASR_STOP, "{}", null, 0, 0);
103 | }
104 |
105 | /**
106 | * 取消本次识别,取消后将立即停止不会返回识别结果。
107 | * cancel 与stop的区别是 cancel在stop的基础上,完全停止整个识别流程,
108 | */
109 | public void cancel() {
110 | Log.i(TAG, "取消识别");
111 | if (!isInited) {
112 | throw new RuntimeException("release() was called");
113 | }
114 | // SDK集成步骤 (可选) 取消本次识别
115 | asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
116 | }
117 |
118 | public void release() {
119 | if (asr == null) {
120 | return;
121 | }
122 | cancel();
123 | if (isOfflineEngineLoaded) {
124 | // SDK集成步骤 如果之前有调用过 加载离线命令词,这里要对应释放
125 | asr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0);
126 | isOfflineEngineLoaded = false;
127 | }
128 | // SDK 集成步骤(可选),卸载listener
129 | asr.unregisterListener(eventListener);
130 | asr = null;
131 | isInited = false;
132 | }
133 |
134 | public void setEventListener(OnAsrListener recogListener) {
135 | if (!isInited) {
136 | throw new RuntimeException("release() was called");
137 | }
138 | this.eventListener = new RecogEventAdapter(recogListener);
139 | asr.registerListener(eventListener);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/java/com/rjx/asr_plugin/AsrPlugin.java:
--------------------------------------------------------------------------------
1 | package com.rjx.asr_plugin;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.pm.PackageManager;
6 | import android.util.Log;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.core.app.ActivityCompat;
10 | import androidx.core.content.ContextCompat;
11 |
12 | import java.util.ArrayList;
13 | import java.util.Map;
14 |
15 | import io.flutter.plugin.common.MethodCall;
16 | import io.flutter.plugin.common.MethodChannel;
17 | import io.flutter.plugin.common.PluginRegistry;
18 |
19 | public class AsrPlugin implements MethodChannel.MethodCallHandler {
20 |
21 | private static final String TAG = "AsrPlugin";
22 | private final Activity activity;
23 | private ResultStateful resultStateful;
24 | private AsrManager asrManager;
25 |
26 | public static void registerWith(PluginRegistry.Registrar registrar) {
27 | //消息地址
28 | MethodChannel channel = new MethodChannel(registrar.messenger(), "asr_plugin");
29 | AsrPlugin instance = new AsrPlugin(registrar);
30 | channel.setMethodCallHandler(instance);
31 | }
32 |
33 | public AsrPlugin(PluginRegistry.Registrar registrar) {
34 | this.activity = registrar.activity();
35 | }
36 |
37 | @Override
38 | public void onMethodCall(MethodCall call, MethodChannel.Result result) {
39 | initPermission();
40 | switch (call.method) {
41 | case "start":
42 | resultStateful = ResultStateful.of(result);
43 | start(call,resultStateful);
44 | break;
45 | case "stop":
46 | stop(call,result);
47 | break;
48 | case "cancel":
49 | cancel(call,result);
50 | break;
51 | default:
52 | break;
53 | }
54 | }
55 |
56 | private void start(MethodCall call, ResultStateful result) {
57 | if(activity == null){
58 | Log.e(TAG,"Ignored start,current activity is null");
59 | result.error("Ignored start,current activity is null",null,null);
60 | return;
61 | }
62 | if(getAsrManager() != null){
63 | getAsrManager().start(call.arguments instanceof Map ? (Map)call.arguments:null);
64 | }else{
65 | Log.e(TAG,"Ignored start,current getAsrManager is null");
66 | result.error("Ignored start,current getAsrManager is null",null,null);
67 | }
68 |
69 | }
70 |
71 | private void stop(MethodCall call,MethodChannel.Result result){
72 | if(asrManager != null){
73 | asrManager.stop();
74 | }
75 | }
76 |
77 | private void cancel(MethodCall call,MethodChannel.Result result){
78 | if(asrManager != null){
79 | asrManager.cancel();
80 | }
81 | }
82 |
83 | @Nullable
84 | private AsrManager getAsrManager(){
85 | if(asrManager == null){
86 | if(activity != null && !activity.isFinishing()){
87 | asrManager = new AsrManager(activity,onAsrListener);
88 | }
89 | }
90 | return asrManager;
91 | }
92 |
93 | /**
94 | * android 6.0 以上需要动态申请权限
95 | */
96 | private void initPermission() {
97 | String permissions[] = {Manifest.permission.RECORD_AUDIO,
98 | Manifest.permission.ACCESS_NETWORK_STATE,
99 | Manifest.permission.INTERNET,
100 | Manifest.permission.WRITE_EXTERNAL_STORAGE
101 | };
102 |
103 | ArrayList toApplyList = new ArrayList();
104 |
105 | for (String perm :permissions){
106 | if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(activity, perm)) {
107 | toApplyList.add(perm);
108 | //进入到这里代表没有权限.
109 |
110 | }
111 | }
112 | String tmpList[] = new String[toApplyList.size()];
113 | if (!toApplyList.isEmpty()){
114 | ActivityCompat.requestPermissions(activity, toApplyList.toArray(tmpList), 123);
115 | }
116 |
117 | }
118 | private OnAsrListener onAsrListener = new OnAsrListener() {
119 | @Override
120 | public void onAsrReady() {
121 |
122 | }
123 |
124 | @Override
125 | public void onAsrBegin() {
126 |
127 | }
128 |
129 | @Override
130 | public void onAsrEnd() {
131 |
132 | }
133 |
134 | @Override
135 | public void onAsrPartialResult(String[] results, RecogResult recogResult) {
136 |
137 | }
138 |
139 | @Override
140 | public void onAsrOnlineNluResult(String nluResult) {
141 |
142 | }
143 |
144 | @Override
145 | public void onAsrFinalResult(String[] results, RecogResult recogResult) {
146 | if(resultStateful != null){
147 | resultStateful.success(results[0]);
148 | }
149 | }
150 |
151 | @Override
152 | public void onAsrFinish(RecogResult recogResult) {
153 |
154 | }
155 |
156 | @Override
157 | public void onAsrFinishError(int errorCode, int subErrorCode, String descMessage, RecogResult recogResult) {
158 | if(resultStateful != null){
159 | resultStateful.error(descMessage,null,null);
160 | }
161 | }
162 |
163 | @Override
164 | public void onAsrLongFinish() {
165 |
166 | }
167 |
168 | @Override
169 | public void onAsrVolume(int volumePercent, int volume) {
170 |
171 | }
172 |
173 | @Override
174 | public void onAsrAudio(byte[] data, int offset, int length) {
175 |
176 | }
177 |
178 | @Override
179 | public void onAsrExit() {
180 |
181 | }
182 |
183 | @Override
184 | public void onOfflineLoaded() {
185 |
186 | }
187 |
188 | @Override
189 | public void onOfflineUnLoaded() {
190 |
191 | }
192 | };
193 | }
194 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/java/com/rjx/asr_plugin/OnAsrListener.java:
--------------------------------------------------------------------------------
1 | package com.rjx.asr_plugin;
2 |
3 |
4 | /**
5 | * 与SDK中回调参数的对应关系定义在RecogEventAdapter类中
6 | */
7 |
8 | public interface OnAsrListener {
9 |
10 | /**
11 | * CALLBACK_EVENT_ASR_READY
12 | * ASR_START 输入事件调用后,引擎准备完毕
13 | */
14 | void onAsrReady();
15 |
16 | /**
17 | * CALLBACK_EVENT_ASR_BEGIN
18 | * onAsrReady后检查到用户开始说话
19 | */
20 | void onAsrBegin();
21 |
22 | /**
23 | * CALLBACK_EVENT_ASR_END
24 | * 检查到用户开始说话停止,或者ASR_STOP 输入事件调用后,
25 | */
26 | void onAsrEnd();
27 |
28 | /**
29 | * CALLBACK_EVENT_ASR_PARTIAL resultType=partial_result
30 | * onAsrBegin 后 随着用户的说话,返回的临时结果
31 | *
32 | * @param results 可能返回多个结果,请取第一个结果
33 | * @param recogResult 完整的结果
34 | */
35 | void onAsrPartialResult(String[] results, RecogResult recogResult);
36 |
37 | /**
38 | * 语音的在线语义结果
39 | *
40 | * CALLBACK_EVENT_ASR_PARTIAL resultType=nlu_result
41 | * @param nluResult
42 | */
43 | void onAsrOnlineNluResult(String nluResult);
44 |
45 | /**
46 | * 不开启长语音仅回调一次,长语音的每一句话都会回调一次
47 | * CALLBACK_EVENT_ASR_PARTIAL resultType=final_result
48 | * 最终的识别结果
49 | *
50 | * @param results 可能返回多个结果,请取第一个结果
51 | * @param recogResult 完整的结果
52 | */
53 | void onAsrFinalResult(String[] results, RecogResult recogResult);
54 |
55 | /**
56 | * CALLBACK_EVENT_ASR_FINISH
57 | * @param recogResult 结束识别
58 | */
59 | void onAsrFinish(RecogResult recogResult);
60 |
61 | /**
62 | * CALLBACK_EVENT_ASR_FINISH error!=0
63 | *
64 | * @param errorCode
65 | * @param subErrorCode
66 | * @param descMessage
67 | * @param recogResult
68 | */
69 | void onAsrFinishError(int errorCode, int subErrorCode, String descMessage,
70 | RecogResult recogResult);
71 |
72 | /**
73 | * 长语音识别结束
74 | */
75 | void onAsrLongFinish();
76 |
77 | /**
78 | * CALLBACK_EVENT_ASR_VOLUME
79 | * 音量回调
80 | *
81 | * @param volumePercent 音量的相对值,百分比,0-100
82 | * @param volume 音量绝对值
83 | */
84 | void onAsrVolume(int volumePercent, int volume);
85 |
86 | /**
87 | * CALLBACK_EVENT_ASR_AUDIO
88 | * @param data pcm格式,16bits 16000采样率
89 | *
90 | * @param offset
91 | * @param length
92 | */
93 | void onAsrAudio(byte[] data, int offset, int length);
94 |
95 | /**
96 | * CALLBACK_EVENT_ASR_EXIT
97 | * 引擎完成整个识别,空闲中
98 | */
99 | void onAsrExit();
100 |
101 | /**
102 | * CALLBACK_EVENT_ASR_LOADED
103 | * 离线命令词资源加载成功
104 | */
105 | void onOfflineLoaded();
106 |
107 | /**
108 | * CALLBACK_EVENT_ASR_UNLOADED
109 | * 离线命令词资源释放成功
110 | */
111 | void onOfflineUnLoaded();
112 | }
113 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/java/com/rjx/asr_plugin/RecogEventAdapter.java:
--------------------------------------------------------------------------------
1 | package com.rjx.asr_plugin;
2 |
3 | import android.util.Log;
4 | import com.baidu.speech.EventListener;
5 | import com.baidu.speech.asr.SpeechConstant;
6 | import org.json.JSONException;
7 | import org.json.JSONObject;
8 |
9 | /**
10 | * Created by fujiayi on 2017/6/14.
11 | */
12 |
13 | public class RecogEventAdapter implements EventListener {
14 |
15 | private OnAsrListener listener;
16 |
17 | private static final String TAG = "RecogEventAdapter";
18 |
19 | public RecogEventAdapter(OnAsrListener listener) {
20 | this.listener = listener;
21 | }
22 |
23 | // 基于DEMO集成3.1 开始回调事件
24 | @Override
25 | public void onEvent(String name, String params, byte[] data, int offset, int length) {
26 | String currentJson = params;
27 | String logMessage = "name:" + name + "; params:" + params;
28 |
29 | // logcat 中 搜索RecogEventAdapter,即可以看见下面一行的日志
30 | Log.i(TAG, logMessage);
31 | if (false) { // 可以调试,不需要后续逻辑
32 | return;
33 | }
34 | if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_LOADED)) {
35 | listener.onOfflineLoaded();
36 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_UNLOADED)) {
37 | listener.onOfflineUnLoaded();
38 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_READY)) {
39 | // 引擎准备就绪,可以开始说话
40 | listener.onAsrReady();
41 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_BEGIN)) {
42 | // 检测到用户的已经开始说话
43 | listener.onAsrBegin();
44 |
45 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_END)) {
46 | // 检测到用户的已经停止说话
47 | listener.onAsrEnd();
48 |
49 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
50 | RecogResult recogResult = RecogResult.parseJson(params);
51 | // 识别结果
52 | String[] results = recogResult.getResultsRecognition();
53 | if (recogResult.isFinalResult()) {
54 | // 最终识别结果,长语音每一句话会回调一次
55 | listener.onAsrFinalResult(results, recogResult);
56 | } else if (recogResult.isPartialResult()) {
57 | // 临时识别结果
58 | listener.onAsrPartialResult(results, recogResult);
59 | } else if (recogResult.isNluResult()) {
60 | // 语义理解结果
61 | listener.onAsrOnlineNluResult(new String(data, offset, length));
62 | }
63 |
64 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_FINISH)) {
65 | // 识别结束
66 | RecogResult recogResult = RecogResult.parseJson(params);
67 | if (recogResult.hasError()) {
68 | int errorCode = recogResult.getError();
69 | int subErrorCode = recogResult.getSubError();
70 | Log.i(TAG, "asr error:" + params);
71 | listener.onAsrFinishError(errorCode, subErrorCode, recogResult.getDesc(), recogResult);
72 | } else {
73 | listener.onAsrFinish(recogResult);
74 | }
75 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_LONG_SPEECH)) { // 长语音
76 | listener.onAsrLongFinish(); // 长语音
77 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_EXIT)) {
78 | listener.onAsrExit();
79 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_VOLUME)) {
80 | // Logger.info(TAG, "asr volume event:" + params);
81 | Volume vol = parseVolumeJson(params);
82 | listener.onAsrVolume(vol.volumePercent, vol.volume);
83 | } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_AUDIO)) {
84 | if (data.length != length) {
85 | Log.e(TAG, "internal error: asr.audio callback data length is not equal to length param");
86 | }
87 | listener.onAsrAudio(data, offset, length);
88 | }
89 | }
90 |
91 | private Volume parseVolumeJson(String jsonStr) {
92 | Volume vol = new Volume();
93 | vol.origalJson = jsonStr;
94 | try {
95 | JSONObject json = new JSONObject(jsonStr);
96 | vol.volumePercent = json.getInt("volume-percent");
97 | vol.volume = json.getInt("volume");
98 | } catch (JSONException e) {
99 | e.printStackTrace();
100 | }
101 | return vol;
102 | }
103 |
104 | private class Volume {
105 | private int volumePercent = -1;
106 | private int volume = -1;
107 | private String origalJson;
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/java/com/rjx/asr_plugin/RecogResult.java:
--------------------------------------------------------------------------------
1 | package com.rjx.asr_plugin;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | /**
8 | * Created by fujiayi on 2017/6/24.
9 | */
10 | public class RecogResult {
11 | private static final int ERROR_NONE = 0;
12 |
13 | private String origalJson;
14 | private String[] resultsRecognition;
15 | private String origalResult;
16 | private String sn; // 日志id, 请求有问题请提问带上sn
17 | private String desc;
18 | private String resultType;
19 | private int error = -1;
20 | private int subError = -1;
21 |
22 | public static RecogResult parseJson(String jsonStr) {
23 | RecogResult result = new RecogResult();
24 | result.setOrigalJson(jsonStr);
25 | try {
26 | JSONObject json = new JSONObject(jsonStr);
27 | int error = json.optInt("error");
28 | int subError = json.optInt("sub_error");
29 | result.setError(error);
30 | result.setDesc(json.optString("desc"));
31 | result.setResultType(json.optString("result_type"));
32 | result.setSubError(subError);
33 | if (error == ERROR_NONE) {
34 | result.setOrigalResult(json.getString("origin_result"));
35 | JSONArray arr = json.optJSONArray("results_recognition");
36 | if (arr != null) {
37 | int size = arr.length();
38 | String[] recogs = new String[size];
39 | for (int i = 0; i < size; i++) {
40 | recogs[i] = arr.getString(i);
41 | }
42 | result.setResultsRecognition(recogs);
43 | }
44 |
45 |
46 | }
47 | } catch (JSONException e) {
48 | e.printStackTrace();
49 | }
50 |
51 | return result;
52 | }
53 |
54 | public boolean hasError() {
55 | return error != ERROR_NONE;
56 | }
57 |
58 | public boolean isFinalResult() {
59 | return "final_result".equals(resultType);
60 | }
61 |
62 |
63 | public boolean isPartialResult() {
64 | return "partial_result".equals(resultType);
65 | }
66 |
67 | public boolean isNluResult() {
68 | return "nlu_result".equals(resultType);
69 | }
70 |
71 | public String getOrigalJson() {
72 | return origalJson;
73 | }
74 |
75 | public void setOrigalJson(String origalJson) {
76 | this.origalJson = origalJson;
77 | }
78 |
79 | public String[] getResultsRecognition() {
80 | return resultsRecognition;
81 | }
82 |
83 | public void setResultsRecognition(String[] resultsRecognition) {
84 | this.resultsRecognition = resultsRecognition;
85 | }
86 |
87 | public String getSn() {
88 | return sn;
89 | }
90 |
91 | public void setSn(String sn) {
92 | this.sn = sn;
93 | }
94 |
95 | public int getError() {
96 | return error;
97 | }
98 |
99 | public void setError(int error) {
100 | this.error = error;
101 | }
102 |
103 | public String getDesc() {
104 | return desc;
105 | }
106 |
107 | public void setDesc(String desc) {
108 | this.desc = desc;
109 | }
110 |
111 | public String getOrigalResult() {
112 | return origalResult;
113 | }
114 |
115 | public void setOrigalResult(String origalResult) {
116 | this.origalResult = origalResult;
117 | }
118 |
119 | public String getResultType() {
120 | return resultType;
121 | }
122 |
123 | public void setResultType(String resultType) {
124 | this.resultType = resultType;
125 | }
126 |
127 | public int getSubError() {
128 | return subError;
129 | }
130 |
131 | public void setSubError(int subError) {
132 | this.subError = subError;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/java/com/rjx/asr_plugin/ResultStateful.java:
--------------------------------------------------------------------------------
1 | package com.rjx.asr_plugin;
2 |
3 | import android.util.Log;
4 |
5 | import io.flutter.plugin.common.MethodChannel;
6 |
7 | public class ResultStateful implements MethodChannel.Result {
8 | private static final String TAG = "ResultStateful";
9 | private MethodChannel.Result result;
10 | private boolean called;
11 |
12 | public ResultStateful(MethodChannel.Result result) {
13 | this.result = result;
14 | }
15 |
16 | public static ResultStateful of(MethodChannel.Result result) {
17 | return new ResultStateful(result);
18 | }
19 |
20 | @Override
21 | public void success(Object o) {
22 | if (called) {
23 | Log.e(TAG, "Has called before");
24 | return;
25 | }
26 | called = true;
27 | this.result.success(o);
28 |
29 |
30 | }
31 |
32 | @Override
33 | public void error(String errorCode, String errorMessage, Object errorDetails) {
34 | if (called) {
35 | Log.e(TAG, "Has called error before");
36 | return;
37 | }
38 | called = true;
39 | this.result.error(errorCode,errorMessage,errorDetails);
40 | }
41 |
42 | @Override
43 | public void notImplemented() {
44 | if (called) {
45 | Log.e(TAG, "Has called not Implemented");
46 | return;
47 | }
48 | called = true;
49 | this.result.notImplemented();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/jniLibs/arm64-v8a/libBaiduSpeechSDK.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/src/main/jniLibs/arm64-v8a/libBaiduSpeechSDK.so
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/jniLibs/arm64-v8a/libvad.dnn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/src/main/jniLibs/arm64-v8a/libvad.dnn.so
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/jniLibs/x86/libBaiduSpeechSDK.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/src/main/jniLibs/x86/libBaiduSpeechSDK.so
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/jniLibs/x86/libvad.dnn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/src/main/jniLibs/x86/libvad.dnn.so
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/jniLibs/x86_64/libBaiduSpeechSDK.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/src/main/jniLibs/x86_64/libBaiduSpeechSDK.so
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/jniLibs/x86_64/libvad.dnn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/asr_plugin/src/main/jniLibs/x86_64/libvad.dnn.so
--------------------------------------------------------------------------------
/android/asr_plugin/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | asr_plugin
3 |
4 |
--------------------------------------------------------------------------------
/android/asr_plugin/src/test/java/com/rjx/asr_plugin/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.rjx.asr_plugin;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
5 | google()
6 | jcenter()
7 | }
8 |
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.5.0'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
18 | google()
19 | jcenter()
20 | }
21 | }
22 |
23 | rootProject.buildDir = '../build'
24 | subprojects {
25 | project.buildDir = "${rootProject.buildDir}/${project.name}"
26 | }
27 | subprojects {
28 | project.evaluationDependsOn(':app')
29 | }
30 |
31 | task clean(type: Delete) {
32 | delete rootProject.buildDir
33 | }
34 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/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-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/key.properties:
--------------------------------------------------------------------------------
1 | storePassword=xiecheng
2 | keyPassword=xiecheng
3 | keyAlias=xiecheng
4 | storeFile=../xiecheng.jks
--------------------------------------------------------------------------------
/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.baidu.sppch.**{*;}
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':asr_plugin'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/android/xiecheng.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/android/xiecheng.jks
--------------------------------------------------------------------------------
/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/app-release.apk
--------------------------------------------------------------------------------
/images/type_channelgroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_channelgroup.png
--------------------------------------------------------------------------------
/images/type_channellgs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_channellgs.png
--------------------------------------------------------------------------------
/images/type_channelplane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_channelplane.png
--------------------------------------------------------------------------------
/images/type_channeltrain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_channeltrain.png
--------------------------------------------------------------------------------
/images/type_cruise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_cruise.png
--------------------------------------------------------------------------------
/images/type_district.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_district.png
--------------------------------------------------------------------------------
/images/type_food.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_food.png
--------------------------------------------------------------------------------
/images/type_hotel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_hotel.png
--------------------------------------------------------------------------------
/images/type_huodong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_huodong.png
--------------------------------------------------------------------------------
/images/type_shop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_shop.png
--------------------------------------------------------------------------------
/images/type_sight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_sight.png
--------------------------------------------------------------------------------
/images/type_ticket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_ticket.png
--------------------------------------------------------------------------------
/images/type_travelgroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/images/type_travelgroup.png
--------------------------------------------------------------------------------
/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/Generated.xcconfig
20 | Flutter/app.flx
21 | Flutter/app.zip
22 | Flutter/flutter_assets/
23 | Flutter/flutter_export_environment.sh
24 | ServiceDefinitions.json
25 | Runner/GeneratedPluginRegistrant.*
26 |
27 | # Exceptions to above rules.
28 | !default.mode1v3
29 | !default.mode2v3
30 | !default.pbxuser
31 | !default.perspectivev3
32 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
17 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
18 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
19 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXCopyFilesBuildPhase section */
23 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
24 | isa = PBXCopyFilesBuildPhase;
25 | buildActionMask = 2147483647;
26 | dstPath = "";
27 | dstSubfolderSpec = 10;
28 | files = (
29 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
30 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
31 | );
32 | name = "Embed Frameworks";
33 | runOnlyForDeploymentPostprocessing = 0;
34 | };
35 | /* End PBXCopyFilesBuildPhase section */
36 |
37 | /* Begin PBXFileReference section */
38 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
39 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
40 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
41 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
42 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
43 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
44 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
45 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
46 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
47 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
48 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
49 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
50 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
51 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
52 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
53 | /* End PBXFileReference section */
54 |
55 | /* Begin PBXFrameworksBuildPhase section */
56 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
57 | isa = PBXFrameworksBuildPhase;
58 | buildActionMask = 2147483647;
59 | files = (
60 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
61 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
62 | );
63 | runOnlyForDeploymentPostprocessing = 0;
64 | };
65 | /* End PBXFrameworksBuildPhase section */
66 |
67 | /* Begin PBXGroup section */
68 | 9740EEB11CF90186004384FC /* Flutter */ = {
69 | isa = PBXGroup;
70 | children = (
71 | 3B80C3931E831B6300D905FE /* App.framework */,
72 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
73 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
74 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
75 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
76 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
77 | );
78 | name = Flutter;
79 | sourceTree = "";
80 | };
81 | 97C146E51CF9000F007C117D = {
82 | isa = PBXGroup;
83 | children = (
84 | 9740EEB11CF90186004384FC /* Flutter */,
85 | 97C146F01CF9000F007C117D /* Runner */,
86 | 97C146EF1CF9000F007C117D /* Products */,
87 | );
88 | sourceTree = "";
89 | };
90 | 97C146EF1CF9000F007C117D /* Products */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 97C146EE1CF9000F007C117D /* Runner.app */,
94 | );
95 | name = Products;
96 | sourceTree = "";
97 | };
98 | 97C146F01CF9000F007C117D /* Runner */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
102 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
103 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
104 | 97C147021CF9000F007C117D /* Info.plist */,
105 | 97C146F11CF9000F007C117D /* Supporting Files */,
106 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
107 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
108 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
109 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
110 | );
111 | path = Runner;
112 | sourceTree = "";
113 | };
114 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
115 | isa = PBXGroup;
116 | children = (
117 | );
118 | name = "Supporting Files";
119 | sourceTree = "";
120 | };
121 | /* End PBXGroup section */
122 |
123 | /* Begin PBXNativeTarget section */
124 | 97C146ED1CF9000F007C117D /* Runner */ = {
125 | isa = PBXNativeTarget;
126 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
127 | buildPhases = (
128 | 9740EEB61CF901F6004384FC /* Run Script */,
129 | 97C146EA1CF9000F007C117D /* Sources */,
130 | 97C146EB1CF9000F007C117D /* Frameworks */,
131 | 97C146EC1CF9000F007C117D /* Resources */,
132 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
133 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
134 | );
135 | buildRules = (
136 | );
137 | dependencies = (
138 | );
139 | name = Runner;
140 | productName = Runner;
141 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
142 | productType = "com.apple.product-type.application";
143 | };
144 | /* End PBXNativeTarget section */
145 |
146 | /* Begin PBXProject section */
147 | 97C146E61CF9000F007C117D /* Project object */ = {
148 | isa = PBXProject;
149 | attributes = {
150 | LastUpgradeCheck = 1020;
151 | ORGANIZATIONNAME = "The Chromium Authors";
152 | TargetAttributes = {
153 | 97C146ED1CF9000F007C117D = {
154 | CreatedOnToolsVersion = 7.3.1;
155 | LastSwiftMigration = 0910;
156 | };
157 | };
158 | };
159 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
160 | compatibilityVersion = "Xcode 3.2";
161 | developmentRegion = en;
162 | hasScannedForEncodings = 0;
163 | knownRegions = (
164 | en,
165 | Base,
166 | );
167 | mainGroup = 97C146E51CF9000F007C117D;
168 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
169 | projectDirPath = "";
170 | projectRoot = "";
171 | targets = (
172 | 97C146ED1CF9000F007C117D /* Runner */,
173 | );
174 | };
175 | /* End PBXProject section */
176 |
177 | /* Begin PBXResourcesBuildPhase section */
178 | 97C146EC1CF9000F007C117D /* Resources */ = {
179 | isa = PBXResourcesBuildPhase;
180 | buildActionMask = 2147483647;
181 | files = (
182 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
183 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
184 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
185 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
186 | );
187 | runOnlyForDeploymentPostprocessing = 0;
188 | };
189 | /* End PBXResourcesBuildPhase section */
190 |
191 | /* Begin PBXShellScriptBuildPhase section */
192 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
193 | isa = PBXShellScriptBuildPhase;
194 | buildActionMask = 2147483647;
195 | files = (
196 | );
197 | inputPaths = (
198 | );
199 | name = "Thin Binary";
200 | outputPaths = (
201 | );
202 | runOnlyForDeploymentPostprocessing = 0;
203 | shellPath = /bin/sh;
204 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
205 | };
206 | 9740EEB61CF901F6004384FC /* Run Script */ = {
207 | isa = PBXShellScriptBuildPhase;
208 | buildActionMask = 2147483647;
209 | files = (
210 | );
211 | inputPaths = (
212 | );
213 | name = "Run Script";
214 | outputPaths = (
215 | );
216 | runOnlyForDeploymentPostprocessing = 0;
217 | shellPath = /bin/sh;
218 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
219 | };
220 | /* End PBXShellScriptBuildPhase section */
221 |
222 | /* Begin PBXSourcesBuildPhase section */
223 | 97C146EA1CF9000F007C117D /* Sources */ = {
224 | isa = PBXSourcesBuildPhase;
225 | buildActionMask = 2147483647;
226 | files = (
227 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
228 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
229 | );
230 | runOnlyForDeploymentPostprocessing = 0;
231 | };
232 | /* End PBXSourcesBuildPhase section */
233 |
234 | /* Begin PBXVariantGroup section */
235 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
236 | isa = PBXVariantGroup;
237 | children = (
238 | 97C146FB1CF9000F007C117D /* Base */,
239 | );
240 | name = Main.storyboard;
241 | sourceTree = "";
242 | };
243 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
244 | isa = PBXVariantGroup;
245 | children = (
246 | 97C147001CF9000F007C117D /* Base */,
247 | );
248 | name = LaunchScreen.storyboard;
249 | sourceTree = "";
250 | };
251 | /* End PBXVariantGroup section */
252 |
253 | /* Begin XCBuildConfiguration section */
254 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
255 | isa = XCBuildConfiguration;
256 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
257 | buildSettings = {
258 | ALWAYS_SEARCH_USER_PATHS = NO;
259 | CLANG_ANALYZER_NONNULL = YES;
260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
261 | CLANG_CXX_LIBRARY = "libc++";
262 | CLANG_ENABLE_MODULES = YES;
263 | CLANG_ENABLE_OBJC_ARC = YES;
264 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
265 | CLANG_WARN_BOOL_CONVERSION = YES;
266 | CLANG_WARN_COMMA = YES;
267 | CLANG_WARN_CONSTANT_CONVERSION = YES;
268 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
270 | CLANG_WARN_EMPTY_BODY = YES;
271 | CLANG_WARN_ENUM_CONVERSION = YES;
272 | CLANG_WARN_INFINITE_RECURSION = YES;
273 | CLANG_WARN_INT_CONVERSION = YES;
274 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
275 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
276 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
278 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
279 | CLANG_WARN_STRICT_PROTOTYPES = YES;
280 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
281 | CLANG_WARN_UNREACHABLE_CODE = YES;
282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
284 | COPY_PHASE_STRIP = NO;
285 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
286 | ENABLE_NS_ASSERTIONS = NO;
287 | ENABLE_STRICT_OBJC_MSGSEND = YES;
288 | GCC_C_LANGUAGE_STANDARD = gnu99;
289 | GCC_NO_COMMON_BLOCKS = YES;
290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
292 | GCC_WARN_UNDECLARED_SELECTOR = YES;
293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
294 | GCC_WARN_UNUSED_FUNCTION = YES;
295 | GCC_WARN_UNUSED_VARIABLE = YES;
296 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
297 | MTL_ENABLE_DEBUG_INFO = NO;
298 | SDKROOT = iphoneos;
299 | SUPPORTED_PLATFORMS = iphoneos;
300 | TARGETED_DEVICE_FAMILY = "1,2";
301 | VALIDATE_PRODUCT = YES;
302 | };
303 | name = Profile;
304 | };
305 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
306 | isa = XCBuildConfiguration;
307 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
308 | buildSettings = {
309 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
310 | CLANG_ENABLE_MODULES = YES;
311 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
312 | ENABLE_BITCODE = NO;
313 | FRAMEWORK_SEARCH_PATHS = (
314 | "$(inherited)",
315 | "$(PROJECT_DIR)/Flutter",
316 | );
317 | INFOPLIST_FILE = Runner/Info.plist;
318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
319 | LIBRARY_SEARCH_PATHS = (
320 | "$(inherited)",
321 | "$(PROJECT_DIR)/Flutter",
322 | );
323 | PRODUCT_BUNDLE_IDENTIFIER = com.rjx.xiechengwangApp;
324 | PRODUCT_NAME = "$(TARGET_NAME)";
325 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
326 | SWIFT_VERSION = 4.0;
327 | VERSIONING_SYSTEM = "apple-generic";
328 | };
329 | name = Profile;
330 | };
331 | 97C147031CF9000F007C117D /* Debug */ = {
332 | isa = XCBuildConfiguration;
333 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
334 | buildSettings = {
335 | ALWAYS_SEARCH_USER_PATHS = NO;
336 | CLANG_ANALYZER_NONNULL = YES;
337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
338 | CLANG_CXX_LIBRARY = "libc++";
339 | CLANG_ENABLE_MODULES = YES;
340 | CLANG_ENABLE_OBJC_ARC = YES;
341 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
342 | CLANG_WARN_BOOL_CONVERSION = YES;
343 | CLANG_WARN_COMMA = YES;
344 | CLANG_WARN_CONSTANT_CONVERSION = YES;
345 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
346 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
347 | CLANG_WARN_EMPTY_BODY = YES;
348 | CLANG_WARN_ENUM_CONVERSION = YES;
349 | CLANG_WARN_INFINITE_RECURSION = YES;
350 | CLANG_WARN_INT_CONVERSION = YES;
351 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
352 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
353 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
355 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
356 | CLANG_WARN_STRICT_PROTOTYPES = YES;
357 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
358 | CLANG_WARN_UNREACHABLE_CODE = YES;
359 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
360 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
361 | COPY_PHASE_STRIP = NO;
362 | DEBUG_INFORMATION_FORMAT = dwarf;
363 | ENABLE_STRICT_OBJC_MSGSEND = YES;
364 | ENABLE_TESTABILITY = YES;
365 | GCC_C_LANGUAGE_STANDARD = gnu99;
366 | GCC_DYNAMIC_NO_PIC = NO;
367 | GCC_NO_COMMON_BLOCKS = YES;
368 | GCC_OPTIMIZATION_LEVEL = 0;
369 | GCC_PREPROCESSOR_DEFINITIONS = (
370 | "DEBUG=1",
371 | "$(inherited)",
372 | );
373 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
374 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
375 | GCC_WARN_UNDECLARED_SELECTOR = YES;
376 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
377 | GCC_WARN_UNUSED_FUNCTION = YES;
378 | GCC_WARN_UNUSED_VARIABLE = YES;
379 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
380 | MTL_ENABLE_DEBUG_INFO = YES;
381 | ONLY_ACTIVE_ARCH = YES;
382 | SDKROOT = iphoneos;
383 | TARGETED_DEVICE_FAMILY = "1,2";
384 | };
385 | name = Debug;
386 | };
387 | 97C147041CF9000F007C117D /* Release */ = {
388 | isa = XCBuildConfiguration;
389 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
390 | buildSettings = {
391 | ALWAYS_SEARCH_USER_PATHS = NO;
392 | CLANG_ANALYZER_NONNULL = YES;
393 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
394 | CLANG_CXX_LIBRARY = "libc++";
395 | CLANG_ENABLE_MODULES = YES;
396 | CLANG_ENABLE_OBJC_ARC = YES;
397 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
398 | CLANG_WARN_BOOL_CONVERSION = YES;
399 | CLANG_WARN_COMMA = YES;
400 | CLANG_WARN_CONSTANT_CONVERSION = YES;
401 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
403 | CLANG_WARN_EMPTY_BODY = YES;
404 | CLANG_WARN_ENUM_CONVERSION = YES;
405 | CLANG_WARN_INFINITE_RECURSION = YES;
406 | CLANG_WARN_INT_CONVERSION = YES;
407 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
408 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
409 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
411 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
412 | CLANG_WARN_STRICT_PROTOTYPES = YES;
413 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
414 | CLANG_WARN_UNREACHABLE_CODE = YES;
415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
416 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
417 | COPY_PHASE_STRIP = NO;
418 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
419 | ENABLE_NS_ASSERTIONS = NO;
420 | ENABLE_STRICT_OBJC_MSGSEND = YES;
421 | GCC_C_LANGUAGE_STANDARD = gnu99;
422 | GCC_NO_COMMON_BLOCKS = YES;
423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
425 | GCC_WARN_UNDECLARED_SELECTOR = YES;
426 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
427 | GCC_WARN_UNUSED_FUNCTION = YES;
428 | GCC_WARN_UNUSED_VARIABLE = YES;
429 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
430 | MTL_ENABLE_DEBUG_INFO = NO;
431 | SDKROOT = iphoneos;
432 | SUPPORTED_PLATFORMS = iphoneos;
433 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
434 | TARGETED_DEVICE_FAMILY = "1,2";
435 | VALIDATE_PRODUCT = YES;
436 | };
437 | name = Release;
438 | };
439 | 97C147061CF9000F007C117D /* Debug */ = {
440 | isa = XCBuildConfiguration;
441 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
442 | buildSettings = {
443 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
444 | CLANG_ENABLE_MODULES = YES;
445 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
446 | ENABLE_BITCODE = NO;
447 | FRAMEWORK_SEARCH_PATHS = (
448 | "$(inherited)",
449 | "$(PROJECT_DIR)/Flutter",
450 | );
451 | INFOPLIST_FILE = Runner/Info.plist;
452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
453 | LIBRARY_SEARCH_PATHS = (
454 | "$(inherited)",
455 | "$(PROJECT_DIR)/Flutter",
456 | );
457 | PRODUCT_BUNDLE_IDENTIFIER = com.rjx.xiechengwangApp;
458 | PRODUCT_NAME = "$(TARGET_NAME)";
459 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
460 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
461 | SWIFT_VERSION = 4.0;
462 | VERSIONING_SYSTEM = "apple-generic";
463 | };
464 | name = Debug;
465 | };
466 | 97C147071CF9000F007C117D /* Release */ = {
467 | isa = XCBuildConfiguration;
468 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
469 | buildSettings = {
470 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
471 | CLANG_ENABLE_MODULES = YES;
472 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
473 | ENABLE_BITCODE = NO;
474 | FRAMEWORK_SEARCH_PATHS = (
475 | "$(inherited)",
476 | "$(PROJECT_DIR)/Flutter",
477 | );
478 | INFOPLIST_FILE = Runner/Info.plist;
479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
480 | LIBRARY_SEARCH_PATHS = (
481 | "$(inherited)",
482 | "$(PROJECT_DIR)/Flutter",
483 | );
484 | PRODUCT_BUNDLE_IDENTIFIER = com.rjx.xiechengwangApp;
485 | PRODUCT_NAME = "$(TARGET_NAME)";
486 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
487 | SWIFT_VERSION = 4.0;
488 | VERSIONING_SYSTEM = "apple-generic";
489 | };
490 | name = Release;
491 | };
492 | /* End XCBuildConfiguration section */
493 |
494 | /* Begin XCConfigurationList section */
495 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
496 | isa = XCConfigurationList;
497 | buildConfigurations = (
498 | 97C147031CF9000F007C117D /* Debug */,
499 | 97C147041CF9000F007C117D /* Release */,
500 | 249021D3217E4FDB00AE95B9 /* Profile */,
501 | );
502 | defaultConfigurationIsVisible = 0;
503 | defaultConfigurationName = Release;
504 | };
505 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
506 | isa = XCConfigurationList;
507 | buildConfigurations = (
508 | 97C147061CF9000F007C117D /* Debug */,
509 | 97C147071CF9000F007C117D /* Release */,
510 | 249021D4217E4FDB00AE95B9 /* Profile */,
511 | );
512 | defaultConfigurationIsVisible = 0;
513 | defaultConfigurationName = Release;
514 | };
515 | /* End XCConfigurationList section */
516 |
517 | };
518 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
519 | }
520 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/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 | xiechengwang_app
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 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/lib/dao/home_dao.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 | import 'package:http/http.dart' as http;
4 | import 'package:xiechengwang_app/model/home_model.dart';
5 |
6 | const HOME_URL = "https://www.devio.org/io/flutter_app/json/home_page.json";
7 |
8 | class HomeDao{
9 | static Future fetch() async{
10 | final response = await http.get(HOME_URL);
11 | if(response.statusCode == 200){
12 | //fix中文乱码
13 | Utf8Decoder utf8decoder = Utf8Decoder();
14 | var result = json.decode(utf8decoder.convert(response.bodyBytes));
15 | return HomeModel.fromJson(result);
16 | }else{
17 | throw Exception("Failed to load home_page.json");
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/lib/dao/search_dao.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 | import 'package:http/http.dart' as http;
4 | import 'package:xiechengwang_app/model/search_model.dart';
5 |
6 |
7 | class SearchDao{
8 | static Future fetch(String url,String keyword) async{
9 | final response = await http.get(url);
10 | if(response.statusCode == 200){
11 | //fix中文乱码
12 | Utf8Decoder utf8decoder = Utf8Decoder();
13 | var result = json.decode(utf8decoder.convert(response.bodyBytes));
14 | SearchModel model = SearchModel.fromJson(result);
15 | model.keyword = keyword;
16 | return model;
17 | }else{
18 | throw Exception("Failed to Search");
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/lib/dao/travel_dao.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'package:http/http.dart' as http;
3 | import 'package:xiechengwang_app/model/travel_model.dart';
4 |
5 | // ignore: non_constant_identifier_names
6 | var Params = {
7 | "districtId": -1,
8 | "groupChannelCode": "tourphoto_global1",
9 | "type": null,
10 | "lat": -180,
11 | "lon": -180,
12 | "locatedDistrictId": 2,
13 | "pagePara": {
14 | "pageIndex": 1,
15 | "pageSize": 10,
16 | "sortType": 9,
17 | "sortDirection": 0
18 | },
19 | "imageCutType": 1,
20 | "head": {
21 | "cid": "09031014111431397988",
22 | "ctok": "",
23 | "cver": "1.0",
24 | "lang": "01",
25 | "sid": "8888",
26 | "syscode": "09",
27 | "auth": null,
28 | "extension": [
29 | {
30 | "name": "protocal",
31 | "value": "https"
32 | }
33 | ]
34 | },
35 | "contentType": "json"
36 |
37 | };
38 | class TravelDao{
39 | static Future fetch(String url,String groupChannelCode,int pageIndex,int pageSize) async{
40 | Map paramsMap = Params['pagePara'];
41 | paramsMap['pageIndex'] = pageIndex;
42 | paramsMap['pageSize'] = pageSize;
43 | Params['groupChannelCode'] = groupChannelCode;
44 |
45 | final response = await http.post(url,body: jsonEncode(Params));
46 | if(response.statusCode == 200){
47 | Utf8Decoder utf8decoder = Utf8Decoder();//fix中文乱码
48 | var result = json.decode(utf8decoder.convert(response.bodyBytes));
49 | return TravelModel.fromJson(result);
50 | }else{
51 | throw Exception("Failed to load travel");
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/lib/dao/travel_tab_dao.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:xiechengwang_app/model/travel_tab_model.dart';
4 | import 'package:http/http.dart' as http;
5 |
6 | const TAB_URL = "https://www.devio.org/io/flutter_app/json/travel_page.json";
7 |
8 | class TravelTabDao{
9 | static Future fetch() async{
10 | final response = await http.get(TAB_URL);
11 | if(response.statusCode == 200){
12 | Utf8Decoder utf8decoder = Utf8Decoder();//fix中文乱码
13 | var result = json.decode(utf8decoder.convert(response.bodyBytes));
14 | return TravelTabModel.fromJson(result);
15 | }else{
16 | throw Exception("Failed to load travel_page.json");
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:xiechengwang_app/navigator/tab_navigator.dart';
3 |
4 |
5 | void main() => runApp(MyApp());
6 |
7 | class MyApp extends StatelessWidget {
8 | // This widget is the root of your application.
9 | @override
10 | Widget build(BuildContext context) {
11 | return MaterialApp(
12 | title: '携程旅行',
13 | theme: ThemeData(
14 | // This is the theme of your application.
15 | //
16 | // Try running your application with "flutter run". You'll see the
17 | // application has a blue toolbar. Then, without quitting the app, try
18 | // changing the primarySwatch below to Colors.green and then invoke
19 | // "hot reload" (press "r" in the console where you ran "flutter run",
20 | // or simply save your changes to "hot reload" in a Flutter IDE).
21 | // Notice that the counter didn't reset back to zero; the application
22 | // is not restarted.
23 | primarySwatch: Colors.blue,
24 | ),
25 | home: TabNavigator()
26 | );
27 | }
28 | }
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/lib/model/common_model.dart:
--------------------------------------------------------------------------------
1 |
2 | class CommonModel{
3 | final String icon;
4 | final String title;
5 | final String url;
6 | final String statusBarColor;
7 | final bool hideAppBar;
8 |
9 | CommonModel({this.icon, this.title, this.url, this.statusBarColor,
10 | this.hideAppBar});
11 |
12 | factory CommonModel.fromJson(Map json) {
13 | return CommonModel(icon: json["icon"],
14 | title: json["title"],
15 | url: json["url"],
16 | statusBarColor: json["statusBarColor"],
17 | hideAppBar: json["hideAppBar"],);
18 | }
19 |
20 | Map toJson() {
21 | return {
22 | "icon": this.icon,
23 | "title": this.title,
24 | "url": this.url,
25 | "statusBarColor": this.statusBarColor,
26 | "hideAppBar": this.hideAppBar,
27 | };
28 | }
29 |
30 |
31 | }
--------------------------------------------------------------------------------
/lib/model/config_mdoel.dart:
--------------------------------------------------------------------------------
1 |
2 | class ConfigModel{
3 |
4 | final String searchUrl;
5 |
6 | ConfigModel(this.searchUrl);
7 |
8 | factory ConfigModel.fromJson(Map json){
9 | return ConfigModel(json['searchUrl']);
10 | }
11 |
12 | Map toJson() {
13 | return {"searchUrl": this.searchUrl,};
14 | }
15 |
16 |
17 | }
--------------------------------------------------------------------------------
/lib/model/grid_nav_model.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:xiechengwang_app/model/common_model.dart';
3 |
4 | class GridNavModel{
5 |
6 | final GridNavItem hotel;
7 | final GridNavItem flight;
8 | final GridNavItem travel;
9 |
10 | GridNavModel({this.hotel, this.flight, this.travel});
11 |
12 | factory GridNavModel.fromJson(Map json) {
13 | return GridNavModel(hotel: GridNavItem.fromJson(json["hotel"]),
14 | flight: GridNavItem.fromJson(json["flight"]),
15 | travel: GridNavItem.fromJson(json["travel"]),);
16 | }
17 |
18 | Map toJson() {
19 | return {"hotel": this.hotel, "flight": this.flight, "travel": this.travel,};
20 | }
21 |
22 | }
23 |
24 | class GridNavItem{
25 | final String startColor;
26 | final String endColor;
27 | final CommonModel mainItem;
28 | final CommonModel item1;
29 | final CommonModel item2;
30 | final CommonModel item3;
31 | final CommonModel item4;
32 |
33 | GridNavItem({this.startColor, this.endColor, this.mainItem, this.item1,
34 | this.item2, this.item3, this.item4});
35 |
36 | factory GridNavItem.fromJson(Map json) {
37 | return GridNavItem(startColor: json["startColor"],
38 | endColor: json["endColor"],
39 | mainItem: CommonModel.fromJson(json["mainItem"]),
40 | item1: CommonModel.fromJson(json["item1"]),
41 | item2: CommonModel.fromJson(json["item2"]),
42 | item3: CommonModel.fromJson(json["item3"]),
43 | item4: CommonModel.fromJson(json["item4"]),);
44 | }
45 |
46 | Map toJson() {
47 | return {
48 | "startColor": this.startColor,
49 | "endColor": this.endColor,
50 | "mainItem": this.mainItem,
51 | "item1": this.item1,
52 | "item2": this.item2,
53 | "item3": this.item3,
54 | "item4": this.item4,
55 | };
56 | }
57 |
58 |
59 | }
--------------------------------------------------------------------------------
/lib/model/home_model.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:xiechengwang_app/model/common_model.dart';
3 | import 'package:xiechengwang_app/model/config_mdoel.dart';
4 | import 'package:xiechengwang_app/model/sales_box_model.dart';
5 |
6 | import 'grid_nav_model.dart';
7 |
8 | class HomeModel{
9 |
10 | final ConfigModel config;
11 | final List bannerList;
12 | final List localNavList;
13 | final GridNavModel gridNav;
14 | final List subNavList;
15 | final SalesBoxModel salesBox;
16 |
17 | HomeModel({this.config, this.bannerList, this.localNavList, this.gridNav,
18 | this.subNavList, this.salesBox});
19 |
20 | factory HomeModel.fromJson(Map json) {
21 | return HomeModel(config: ConfigModel.fromJson(json["config"]),
22 | bannerList: List.of(json["bannerList"]).map((
23 | i) => CommonModel.fromJson(i)).toList(),
24 | localNavList: List.of(json["localNavList"]).map((
25 | i) => CommonModel.fromJson(i)).toList(),
26 | gridNav: GridNavModel.fromJson(json["gridNav"]),
27 | subNavList: List.of(json["subNavList"]).map((
28 | i) => CommonModel.fromJson(i)).toList(),
29 | salesBox: SalesBoxModel.fromJson(json["salesBox"]),);
30 | }
31 |
32 | Map toJson() {
33 | return {
34 | "config": this.config,
35 | "bannerList": jsonEncode(this.bannerList),
36 | "localNavList": jsonEncode(this.localNavList),
37 | "gridNav": this.gridNav,
38 | "subNavList": jsonEncode(this.subNavList),
39 | "salesBox": this.salesBox,
40 | };
41 | }
42 | static List jsonEncode(List list){
43 | List jsonList = List();
44 | list.map((item)=>
45 | jsonList.add(item.toJson())
46 | ).toList();
47 | return jsonList;
48 | }
49 |
50 |
51 | }
--------------------------------------------------------------------------------
/lib/model/sales_box_model.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:xiechengwang_app/model/common_model.dart';
3 |
4 | class SalesBoxModel{
5 | final String icon;
6 | final String moreUrl;
7 | final CommonModel bigCard1;
8 | final CommonModel bigCard2;
9 | final CommonModel smallCard1;
10 | final CommonModel smallCard2;
11 | final CommonModel smallCard3;
12 | final CommonModel smallCard4;
13 |
14 | SalesBoxModel({this.icon, this.moreUrl, this.bigCard1, this.bigCard2,
15 | this.smallCard1, this.smallCard2,this.smallCard3,this.smallCard4});
16 |
17 | factory SalesBoxModel.fromJson(Map json) {
18 | return SalesBoxModel(icon: json["icon"],
19 | moreUrl: json["moreUrl"],
20 | bigCard1: CommonModel.fromJson(json["bigCard1"]),
21 | bigCard2: CommonModel.fromJson(json["bigCard2"]),
22 | smallCard1: CommonModel.fromJson(json["smallCard1"]),
23 | smallCard2: CommonModel.fromJson(json["smallCard2"]),
24 | smallCard3: CommonModel.fromJson(json["smallCard3"]),
25 | smallCard4: CommonModel.fromJson(json["smallCard4"]),
26 | );
27 | }
28 |
29 | Map toJson() {
30 | return {
31 | "icon": this.icon,
32 | "moreUrl": this.moreUrl,
33 | "bigCard1": this.bigCard1,
34 | "bigCard2": this.bigCard2,
35 | "smallCard1": this.smallCard1,
36 | "smallCard2": this.smallCard2,
37 | "smallCard3": this.smallCard3,
38 | "smallCard4": this.smallCard4,
39 | };
40 | }
41 |
42 |
43 | }
--------------------------------------------------------------------------------
/lib/model/search_model.dart:
--------------------------------------------------------------------------------
1 | //搜索模型
2 | class SearchModel {
3 | String keyword;
4 | final List data;
5 |
6 | SearchModel({this.data,this.keyword});
7 |
8 | factory SearchModel.fromJson(Map json) {
9 | return SearchModel(
10 | data: List.of(json["data"])
11 | .map((i) => SearchItem.fromJson(i))
12 | .toList(),
13 | );
14 | }
15 | }
16 |
17 | class SearchItem {
18 | final String word; //xxx酒店
19 | final String type; //hotel
20 | final String price; //实时计价
21 | final String zonename; //虹桥
22 | final String districtname; //上海
23 | final String url;
24 | final String star;
25 |
26 | SearchItem(
27 | {this.word,
28 | this.type,
29 | this.price,
30 | this.zonename,
31 | this.districtname,
32 | this.url,this.star});
33 |
34 | factory SearchItem.fromJson(Map json) {
35 | return SearchItem(
36 | word: json["word"],
37 | type: json["type"],
38 | price: json["price"],
39 | zonename: json["zonename"],
40 | districtname: json["districtname"],
41 | url: json["url"],
42 | star: json["star"]
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/model/travel_model.dart:
--------------------------------------------------------------------------------
1 | ///旅拍类别模型
2 | class TravelModel {
3 | int totalCount;
4 | List resultList;
5 |
6 | TravelModel({this.totalCount, this.resultList});
7 |
8 | factory TravelModel.fromJson(Map json) {
9 | return TravelModel(totalCount: json["totalCount"],
10 | resultList: List.of(json["resultList"]).map((
11 | i) => TravelItem.fromJson(i)).toList(),);
12 | }
13 |
14 | }
15 | class TravelItem{
16 |
17 | int type;
18 | Article article;
19 |
20 | TravelItem({this.type, this.article});
21 |
22 | factory TravelItem.fromJson(Map json) {
23 | return TravelItem(type: json["type"],
24 | article: Article.fromJson(json["article"]),);
25 | }
26 |
27 | }
28 | class Article{
29 | int articleId;
30 | String articleType;
31 | int productType;
32 | int sourceType;
33 | String articleTitle;
34 | Author author;
35 | List images;
36 | bool hasVideo;
37 | int readCount;
38 | int likeCount;
39 | int commentCount;
40 | List urls;
41 | List topics;
42 | List pois;
43 | String publishTime;
44 | String publishTimeDisplay;
45 | String shootTime;
46 | String shootTimeDisplay;
47 | int level;
48 | String distanceText;
49 | bool isLike;
50 | int collectCount;
51 | int articleStatus;
52 | String poiName;
53 |
54 | Article({this.articleId, this.articleType, this.productType, this.sourceType,
55 | this.articleTitle, this.author, this.images, this.hasVideo,
56 | this.readCount, this.likeCount, this.commentCount, this.urls,
57 | this.topics, this.pois, this.publishTime, this.publishTimeDisplay,
58 | this.shootTime, this.shootTimeDisplay, this.level, this.distanceText,
59 | this.isLike, this.collectCount, this.articleStatus, this.poiName});
60 |
61 | factory Article.fromJson(Map json) {
62 | return Article(articleId: json["articleId"],
63 | articleType: json["articleType"],
64 | productType: json["productType"],
65 | sourceType: json["sourceType"],
66 | articleTitle: json["articleTitle"],
67 | author: Author.fromJson(json["author"]),
68 | images: List.of(json["images"]).map((
69 | i) => Images.fromJson(i)).toList(),
70 | hasVideo: json["hasVideo"],
71 | readCount: json["readCount"],
72 | likeCount: json["likeCount"],
73 | commentCount: json["commentCount"],
74 | urls: List.of(json["urls"]).map((
75 | i) => Urls.fromJson(i)).toList(),
76 | topics: List.of(json["topics"]).map((
77 | i) => Topics.fromJson(i)).toList(),
78 | pois: List.of(json["pois"]).map((
79 | i) => Pois.fromJson(i)).toList(),
80 | publishTime: json["publishTime"],
81 | publishTimeDisplay: json["publishTimeDisplay"],
82 | shootTime: json["shootTime"],
83 | shootTimeDisplay: json["shootTimeDisplay"],
84 | level: json["level"],
85 | distanceText: json["distanceText"],
86 | isLike: json["isLike"],
87 | collectCount: json["collectCount"],
88 | articleStatus: json["articleStatus"],
89 | poiName: json["poiName"],);
90 | }
91 |
92 |
93 | }
94 | class Author{
95 | int authorId;
96 | String nickName;
97 | String clientAuth;
98 | String jumpUrl;
99 | CoverImage coverImage;
100 | int identityType;
101 | String tag;
102 |
103 | Author({this.authorId, this.nickName, this.clientAuth, this.jumpUrl,
104 | this.coverImage, this.identityType, this.tag});
105 |
106 | factory Author.fromJson(Map json) {
107 | return Author(authorId: json["authorId"],
108 | nickName: json["nickName"],
109 | clientAuth: json["clientAuth"],
110 | jumpUrl: json["jumpUrl"],
111 | coverImage: CoverImage.fromJson(json["coverImage"]),
112 | identityType: json["identityType"],
113 | tag: json["tag"],);
114 | }
115 |
116 |
117 | }
118 |
119 | class Images{
120 | int imageId;
121 | String dynamicUrl;
122 | String originalUrl;
123 | double width;
124 | double height;
125 | int mediaType;
126 | bool isWaterMarked;
127 |
128 | Images({this.imageId, this.dynamicUrl, this.originalUrl, this.width,
129 | this.height, this.mediaType, this.isWaterMarked});
130 |
131 | factory Images.fromJson(Map json) {
132 | return Images(imageId:json["imageId"],
133 | dynamicUrl: json["dynamicUrl"],
134 | originalUrl: json["originalUrl"],
135 | width: json["width"],
136 | height: json["height"],
137 | mediaType: json["mediaType"],
138 | isWaterMarked: json["isWaterMarked"],);
139 | }
140 |
141 | }
142 | class CoverImage{
143 | String dynamicUrl;
144 | String originalUrl;
145 |
146 | CoverImage({this.dynamicUrl, this.originalUrl});
147 |
148 | factory CoverImage.fromJson(Map json) {
149 | return CoverImage(
150 | dynamicUrl: json["dynamicUrl"], originalUrl: json["originalUrl"],);
151 | }
152 |
153 | }
154 |
155 | class Urls{
156 | String version;
157 | String appUrl;
158 | String h5Url;
159 | String wxUrl;
160 |
161 | Urls({this.version, this.appUrl, this.h5Url, this.wxUrl});
162 |
163 | factory Urls.fromJson(Map json) {
164 | return Urls(version: json["version"],
165 | appUrl: json["appUrl"],
166 | h5Url: json["h5Url"],
167 | wxUrl: json["wxUrl"],);
168 | }
169 |
170 | }
171 |
172 | class Topics{
173 | int topicId;
174 | String topicName;
175 | int level;
176 |
177 | Topics({this.topicId, this.topicName, this.level});
178 |
179 | factory Topics.fromJson(Map json) {
180 | return Topics(topicId: json["topicId"],
181 | topicName: json["topicName"],
182 | level: json["level"],);
183 | }
184 |
185 | }
186 | class Pois{
187 | int poiType;
188 | int poiId;
189 | String poiName;
190 | int businessId;
191 | int districtId;
192 | PoiExt poiExt;
193 | int source;
194 | int isMain;
195 | bool isInChina;
196 | String countryName;
197 |
198 | Pois({this.poiType, this.poiId, this.poiName, this.businessId, this.districtId,
199 | this.poiExt, this.source, this.isMain, this.isInChina, this.countryName});
200 |
201 | factory Pois.fromJson(Map json) {
202 | return Pois(poiType: json["poiType"],
203 | poiId: json["poiId"],
204 | poiName: json["poiName"],
205 | businessId: json["businessId"],
206 | districtId:json["districtId"],
207 | poiExt: PoiExt.fromJson(json["poiExt"]),
208 | source: json["source"],
209 | isMain: json["isMain"],
210 | isInChina: json["isInChina"],
211 | countryName: json["countryName"],);
212 | }
213 |
214 |
215 |
216 | }
217 |
218 | class PoiExt{
219 | String h5Url;
220 | String appUrl;
221 |
222 | PoiExt({this.h5Url, this.appUrl});
223 |
224 | factory PoiExt.fromJson(Map json) {
225 | return PoiExt(h5Url: json["h5Url"], appUrl: json["appUrl"],);
226 | }
227 |
228 |
229 |
230 | }
--------------------------------------------------------------------------------
/lib/model/travel_tab_model.dart:
--------------------------------------------------------------------------------
1 | class TravelTabModel {
2 | String url;
3 | List tabs;
4 |
5 | TravelTabModel({this.url, this.tabs});
6 |
7 |
8 | factory TravelTabModel.fromJson(Map json) {
9 | return TravelTabModel(url: json["url"],
10 | tabs: List.of(json["tabs"]).map((
11 | i) => TravelTab.fromJson(i)).toList(),);
12 | }
13 |
14 | Map toJson() {
15 | final Map data = new Map();
16 | data['url'] = this.url;
17 | if (this.tabs != null) {
18 | data['tabs'] = this.tabs.map((v) => v.toJson()).toList();
19 | }
20 | return data;
21 | }
22 | }
23 |
24 | class TravelTab {
25 | String labelName;
26 | String groupChannelCode;
27 |
28 | TravelTab({this.labelName, this.groupChannelCode});
29 |
30 | TravelTab.fromJson(Map json) {
31 | labelName = json['labelName'];
32 | groupChannelCode = json['groupChannelCode'];
33 | }
34 |
35 | Map toJson() {
36 | final Map data = new Map();
37 | data['labelName'] = this.labelName;
38 | data['groupChannelCode'] = this.groupChannelCode;
39 | return data;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/navigator/tab_navigator.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:xiechengwang_app/pages/home_page.dart';
3 | import 'package:xiechengwang_app/pages/my_page.dart';
4 | import 'package:xiechengwang_app/pages/search_page.dart';
5 | import 'package:xiechengwang_app/pages/travel_page.dart';
6 |
7 | class TabNavigator extends StatefulWidget {
8 | @override
9 | State createState() {
10 | // TODO: implement createState
11 | return _TabNavigatorState();
12 | }
13 | }
14 |
15 | class _TabNavigatorState extends State {
16 | final _defaultColor = Colors.grey;
17 | final _activeColor = Colors.blue;
18 | int _currentIndex = 0;
19 |
20 | final PageController _controller = PageController(
21 | initialPage: 0,
22 | );
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | // TODO: implement build
27 | return Scaffold(
28 | body: PageView(
29 | controller: _controller,
30 | children: [
31 | HomePage(),
32 | SearchPage(hideLeft: true,),
33 | TravelPage(),
34 | MyPage()],
35 | //禁止滑动
36 | physics: NeverScrollableScrollPhysics(),
37 | ),
38 | bottomNavigationBar: BottomNavigationBar(
39 | currentIndex: _currentIndex,
40 | onTap: (index) {
41 | _controller.jumpToPage(index);
42 | setState(() {
43 | _currentIndex = index;
44 | });
45 | },
46 | type: BottomNavigationBarType.fixed,
47 | items: [
48 | _bottomNavigationBar("首页",Icons.home,0),
49 | _bottomNavigationBar("搜索",Icons.search,1),
50 | _bottomNavigationBar("旅拍",Icons.camera_alt,2),
51 | _bottomNavigationBar("我的",Icons.account_circle,3),
52 | ],
53 | ),
54 | );
55 | }
56 |
57 | _bottomNavigationBar(String title, IconData icon, int index) {
58 | return BottomNavigationBarItem(
59 | icon: Icon(icon, color: _defaultColor,),
60 | activeIcon: Icon(icon, color: _activeColor,),
61 | title:Text(title,style: TextStyle(color: _currentIndex !=index ? _defaultColor:_activeColor),),
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/pages/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_splash_screen/flutter_splash_screen.dart';
5 | import 'package:flutter_swiper/flutter_swiper.dart';
6 | import 'package:xiechengwang_app/dao/home_dao.dart';
7 | import 'package:xiechengwang_app/model/common_model.dart';
8 | import 'package:xiechengwang_app/model/grid_nav_model.dart';
9 | import 'package:xiechengwang_app/model/sales_box_model.dart';
10 | import 'package:xiechengwang_app/pages/search_page.dart';
11 | import 'package:xiechengwang_app/pages/speak_page.dart';
12 | import 'package:xiechengwang_app/util/navigator_util.dart';
13 | import 'package:xiechengwang_app/widget/grid_nav.dart';
14 | import 'package:xiechengwang_app/widget/loading_container.dart';
15 | import 'package:xiechengwang_app/widget/local_nav.dart';
16 | import 'package:xiechengwang_app/widget/sales_box.dart';
17 | import 'package:xiechengwang_app/widget/search_bar.dart';
18 | import 'package:xiechengwang_app/widget/sub_nav.dart';
19 | import 'package:xiechengwang_app/widget/webview.dart';
20 |
21 | const APPBAR_SCROLL_OFFSET = 100;
22 | const String SEARCH_BAR_DEFAULT_TEXT = "网红打卡地 景点 酒店 美食";
23 |
24 | class HomePage extends StatefulWidget{
25 | @override
26 | _HomePageState createState() {
27 | // TODO: implement createState
28 | return _HomePageState();
29 | }
30 | }
31 |
32 | class _HomePageState extends State with AutomaticKeepAliveClientMixin{
33 | List localNavList = [];
34 | GridNavModel gridNavModel;
35 | List subNavList = [];
36 | List bannerList = [];
37 | SalesBoxModel salesBoxModel;
38 | bool _loading = true;
39 |
40 | String resultString = "";
41 | double appBarAlpha = 0;
42 |
43 | @override
44 | void initState() {
45 | super.initState();
46 | _handleRefresh();
47 | //关闭启动屏
48 | Future.delayed(Duration(milliseconds: 600),(){
49 | FlutterSplashScreen.hide();
50 | });
51 |
52 | }
53 |
54 | Future _handleRefresh() {
55 | return HomeDao.fetch().then((result) {
56 | setState(() {
57 | bannerList = result.bannerList;
58 | localNavList = result.localNavList;
59 | gridNavModel = result.gridNav;
60 | subNavList = result.subNavList;
61 | salesBoxModel = result.salesBox;
62 | _loading = false;
63 | });
64 | }).catchError((error) {
65 | print(error.toString());
66 | _loading = false;
67 | });
68 |
69 | // HomeModel model = await HomeDao.fetch();
70 | // setState(() {
71 | // resultString = json.encode(model);
72 | // });
73 | }
74 |
75 | _onScroll(offset) {
76 | double alpha = offset / APPBAR_SCROLL_OFFSET;
77 |
78 | if (alpha < 0) {
79 | alpha = 0;
80 | } else if (alpha > 1) {
81 | alpha = 1;
82 | }
83 |
84 | setState(() {
85 | appBarAlpha = alpha;
86 | });
87 | }
88 |
89 | @override
90 | Widget build(BuildContext context) {
91 | // TODO: implement build
92 | return Scaffold(
93 | backgroundColor: Color(0xfff2f2),
94 | body: LoadingContainer(
95 | isLoading: _loading,
96 | child: Stack(
97 | children: [
98 | MediaQuery.removePadding(
99 | context: context,
100 | removeTop: true,
101 | child: RefreshIndicator(
102 | //下拉刷新
103 | onRefresh: _handleRefresh,
104 | child: NotificationListener(
105 | onNotification: (scrollNotification) {
106 | if (scrollNotification is ScrollUpdateNotification &&
107 | scrollNotification.depth == 0) {
108 | _onScroll(scrollNotification.metrics.pixels);
109 | }
110 | return;
111 | },
112 | child: _listView,
113 | ),
114 | )),
115 | _appBar,
116 | ],
117 | ),
118 | ));
119 | }
120 |
121 | Widget get _listView {
122 | return ListView(
123 | children: [
124 | _bannerView,
125 | Padding(
126 | padding: EdgeInsets.fromLTRB(7, 4, 7, 4),
127 | child: LocalNav(
128 | localNavList: localNavList,
129 | ),
130 | ),
131 | Padding(
132 | padding: EdgeInsets.fromLTRB(7, 0, 7, 4),
133 | child: GridNav(gridNavModel: gridNavModel),
134 | ),
135 | Padding(
136 | padding: EdgeInsets.fromLTRB(7, 0, 7, 4),
137 | child: SubNav(subNavList: subNavList),
138 | ),
139 | Padding(
140 | padding: EdgeInsets.fromLTRB(7, 0, 7, 4),
141 | child: SalesBox(salesBox: salesBoxModel),
142 | ),
143 | ],
144 | );
145 | }
146 |
147 | Widget get _appBar {
148 | // return Opacity(
149 | // opacity: appBarAlpha,
150 | // child: Container(
151 | // height: 70,
152 | // decoration: BoxDecoration(color: Colors.white),
153 | // alignment: Alignment.center,
154 | // padding: EdgeInsets.only(top: MediaQueryData.fromWindow(window).padding.top),
155 | // child: Text("首页")
156 | // ,
157 | // ),
158 | // );
159 | return Column(
160 | children: [
161 | Container(
162 | decoration: BoxDecoration(
163 | gradient: LinearGradient(
164 | //AppBar渐变遮罩背景
165 | colors: [Color(0x66000000), Colors.transparent],
166 | begin: Alignment.topCenter,
167 | end: Alignment.bottomCenter,
168 | ),
169 | ),
170 | child: Container(
171 | padding: EdgeInsets.fromLTRB(0, MediaQueryData.fromWindow(window).padding.top, 0, 0),
172 | height: 80,
173 | alignment: Alignment.center,
174 | decoration: BoxDecoration(
175 | color:
176 | Color.fromARGB((appBarAlpha * 255).toInt(), 255, 255, 255)),
177 | child: SearchBar(
178 | searchBarType: appBarAlpha > 0.3
179 | ? SearchBarType.homeLight
180 | : SearchBarType.home,
181 | inputBoxClick: _jumpToSearch,
182 | speakClick: _jumpToSpeak,
183 | defaultText: SEARCH_BAR_DEFAULT_TEXT,
184 | leftButtonClick: () {},
185 | ),
186 | ),
187 | ),
188 | //阴影设置
189 | Container(
190 | height: appBarAlpha > 0.3 ? 0.5 : 0,
191 | decoration: BoxDecoration(
192 | boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 0.5)]),
193 | ),
194 | ],
195 | );
196 | }
197 |
198 | Widget get _bannerView {
199 | return Container(
200 | height: 160,
201 | child: Swiper(
202 | itemCount: bannerList.length,
203 | autoplay: true,
204 | itemBuilder: (BuildContext context, int index) {
205 | return GestureDetector(
206 | onTap: () {
207 | CommonModel model = bannerList[index];
208 | NavigatorUtil.push(context, WebView(
209 | url: model.url,
210 | title: model.title,
211 | hideAppBar: model.hideAppBar));
212 | },
213 | child: Image.network(
214 | bannerList[index].icon,
215 | fit: BoxFit.fill,
216 | ),
217 | );
218 | },
219 | pagination: SwiperPagination(), //指示器
220 | ),
221 | );
222 | }
223 |
224 | _jumpToSearch() {
225 | NavigatorUtil.push(context, SearchPage(hint: SEARCH_BAR_DEFAULT_TEXT,));
226 | }
227 |
228 |
229 | _jumpToSpeak() {
230 | NavigatorUtil.push(context, SpeakPage());
231 | }
232 |
233 | @override
234 | bool get wantKeepAlive => true;
235 | }
236 |
--------------------------------------------------------------------------------
/lib/pages/my_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:xiechengwang_app/widget/webview.dart';
3 |
4 | class MyPage extends StatefulWidget {
5 | @override
6 | _MyPageState createState() {
7 | // TODO: implement createState
8 | return _MyPageState();
9 | }
10 | }
11 |
12 | class _MyPageState extends State {
13 | @override
14 | Widget build(BuildContext context) {
15 | // TODO: implement build
16 | return Scaffold(
17 | body: WebView(
18 | url: "https://m.ctrip.com/webapp/myctrip/",
19 | hideAppBar: true,
20 | backForbid: true,
21 | statusBarColor: "4c5bca",
22 | ),
23 | );
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/lib/pages/search_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:xiechengwang_app/dao/search_dao.dart';
5 | import 'package:xiechengwang_app/model/search_model.dart';
6 | import 'package:xiechengwang_app/pages/speak_page.dart';
7 | import 'package:xiechengwang_app/util/navigator_util.dart';
8 | import 'package:xiechengwang_app/widget/search_bar.dart';
9 | import 'package:xiechengwang_app/widget/webview.dart';
10 |
11 | //首页接口的searchUrl返回了该接口
12 | const URL =
13 | "https://m.ctrip.com/restapi/h5api/searchapp/search?source=mobileweb&action=autocomplete&contentType=json&keyword=";
14 |
15 | const TYPES = [
16 | 'channelgroup',
17 | 'channellgs',
18 | 'channelplane',
19 | 'channeltrain',
20 | 'cruise',
21 | 'district',
22 | 'food',
23 | 'hotel',
24 | 'huodong',
25 | 'shop',
26 | 'sight',
27 | 'ticket',
28 | 'travelgroup'
29 | ];
30 |
31 | class SearchPage extends StatefulWidget {
32 | final bool hideLeft;
33 | final String searchUrl;
34 | final String keyword;
35 | final String hint;
36 |
37 | const SearchPage(
38 | {Key key, this.hideLeft, this.searchUrl = URL, this.keyword, this.hint})
39 | : super(key: key);
40 |
41 | @override
42 | _SearchPage createState() {
43 | return _SearchPage();
44 | }
45 | }
46 |
47 | class _SearchPage extends State {
48 | String keyword;
49 | SearchModel searchModel;
50 |
51 | @override
52 | void initState() {
53 | if(widget.keyword != null){
54 | _onTextChange(widget.keyword);
55 | }
56 | super.initState();
57 | }
58 | @override
59 | Widget build(BuildContext context) {
60 | // TODO: implement build
61 | return Scaffold(
62 | body: Column(
63 | children: [
64 | _appBar(),
65 | MediaQuery.removePadding(
66 | context: context,
67 | removeTop: true,
68 | child: Expanded(
69 | flex: 1,
70 | //顶部会有空白 用MediaQuery.removePadding
71 | child: ListView.builder(
72 | itemCount: searchModel?.data?.length ?? 0,
73 | itemBuilder: (BuildContext context, int position) {
74 | return _item(position);
75 | }),
76 | ),
77 | ),
78 | ],
79 | ),
80 | );
81 | }
82 |
83 | _onTextChange(String text) {
84 | //发起请求
85 | keyword = text;
86 | if (text.length == 0) {
87 | setState(() {
88 | searchModel = null;
89 | });
90 | return;
91 | }
92 | String url = widget.searchUrl + keyword;
93 | SearchDao.fetch(url, keyword).then((model) {
94 | if (model.keyword == keyword) {
95 | //解决快速请求展示结果不是最后一次搜索结果的问题
96 | setState(() {
97 | searchModel = model;
98 | });
99 | }
100 | }).catchError((e) {
101 | print(e.toString());
102 | });
103 | }
104 |
105 | _item(int position) {
106 | if (searchModel == null || searchModel.data == null) {
107 | return null;
108 | }
109 | SearchItem item = searchModel.data[position];
110 | return GestureDetector(
111 | onTap: () {
112 | NavigatorUtil.push(context, WebView(url: item.url, title: "详情"));
113 | },
114 | child: Container(
115 | padding: EdgeInsets.all(10),
116 | decoration: BoxDecoration(
117 | border: Border(bottom: BorderSide(width: 0.3, color: Colors.grey))),
118 | child: Row(
119 | children: [
120 | Container(
121 | margin: EdgeInsets.all(1),
122 | child: Image(
123 | height: 26,
124 | width: 26,
125 | image: AssetImage(_typeImage(item.type)),
126 | ),
127 | ),
128 | Column(
129 | children: [
130 | Container(width: 300, child: _title(item)),
131 | Container(
132 | margin: EdgeInsets.only(top: 5),
133 | width: 300,
134 | child: _subTitle(item),
135 | )
136 | ],
137 | )
138 | ],
139 | ),
140 | ),
141 | );
142 | }
143 |
144 | _appBar() {
145 | return Column(
146 | children: [
147 | Container(
148 | decoration: BoxDecoration(
149 | gradient: LinearGradient(
150 | colors: [Color(0x66000000), Colors.transparent],
151 | begin: Alignment.topCenter,
152 | end: Alignment.bottomCenter,
153 | ),
154 | ),
155 | child: Container(
156 | padding: EdgeInsets.only(
157 | top: MediaQueryData.fromWindow(window).padding.top),
158 | height: 80,
159 | alignment: Alignment.center,
160 | decoration: BoxDecoration(color: Colors.white),
161 | child: SearchBar(
162 | hideLeft: widget.hideLeft,
163 | defaultText: widget.keyword,
164 | hint: widget.hint,
165 | speakClick: _jumpToSpeak,
166 | leftButtonClick: () {
167 | Navigator.pop(context);
168 | },
169 | onChanged: _onTextChange,
170 | ),
171 | ),
172 | ),
173 | ],
174 | );
175 | }
176 |
177 | _typeImage(String type) {
178 | if (type == null) {
179 | return "images/type_travelgroup.png";
180 | }
181 | String path = 'travelgroup';
182 | for (final val in TYPES) {
183 | if (type.contains(val)) {
184 | path = val;
185 | break;
186 | }
187 | }
188 | return "images/type_$path.png";
189 | }
190 |
191 | _title(SearchItem item) {
192 | if (item == null) {
193 | return null;
194 | }
195 | List spans = [];
196 | spans.addAll(_keywordTextSpans(item.word, searchModel.keyword));
197 | spans.add(TextSpan(
198 | text: ' ' + (item.districtname ?? "") + " " + (item.zonename ?? ""),
199 | style: TextStyle(fontSize: 16, color: Colors.grey)));
200 | return RichText(text: TextSpan(children: spans));
201 | }
202 |
203 | _subTitle(SearchItem item) {
204 | return RichText(
205 | text: TextSpan(children: [
206 | TextSpan(
207 | text: item.price ?? "",
208 | style: TextStyle(fontSize: 16, color: Colors.orange)),
209 | TextSpan(
210 | text: ' ' + (item.star ?? ''),
211 | style: TextStyle(fontSize: 12, color: Colors.grey))
212 | ]),
213 | );
214 | }
215 |
216 | _keywordTextSpans(String word, String keyword) {
217 | List spans = [];
218 | if (word == null || word.length == 0) {
219 | return spans;
220 | }
221 |
222 | List arr = word.split(keyword);
223 | TextStyle normalStyle = TextStyle(fontSize: 16, color: Colors.black87);
224 | TextStyle keywordStyle = TextStyle(fontSize: 16, color: Colors.orange);
225 | // wordwoc split w [,ord,c]
226 | for (int i = 0; i < arr.length; i++) {
227 | if ((i + 1) % 2 == 0) {
228 | spans.add(TextSpan(text: keyword, style: keywordStyle));
229 | }
230 | String val = arr[i];
231 | if (val != null && val.length > 0) {
232 | spans.add(TextSpan(text: val, style: normalStyle));
233 | }
234 | }
235 | return spans;
236 | }
237 |
238 | _jumpToSpeak() {
239 | NavigatorUtil.push(context, SpeakPage());
240 | }
241 | }
242 |
--------------------------------------------------------------------------------
/lib/pages/speak_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:xiechengwang_app/pages/search_page.dart';
4 | import 'package:xiechengwang_app/plugin/asr_manager.dart';
5 | import 'package:xiechengwang_app/util/navigator_util.dart';
6 |
7 | class SpeakPage extends StatefulWidget {
8 | @override
9 | _SpeakPageState createState() {
10 | return _SpeakPageState();
11 | }
12 | }
13 |
14 | class _SpeakPageState extends State
15 | with SingleTickerProviderStateMixin {
16 | String speakTips = "长按说话";
17 | String speakResult = "";
18 | Animation animation;
19 | AnimationController controller;
20 |
21 | @override
22 | void initState() {
23 | controller = AnimationController(
24 | vsync: this, duration: Duration(milliseconds: 1000));
25 | animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)
26 | ..addStatusListener((status) {
27 | //动画放大缩小 可以通过
28 | if (status == AnimationStatus.completed) {
29 | controller.reverse();
30 | } else if (status == AnimationStatus.dismissed) {
31 | controller.forward();
32 | }
33 | });
34 | super.initState();
35 | }
36 |
37 | @override
38 | void dispose() {
39 | controller.dispose();
40 | super.dispose();
41 | }
42 |
43 | @override
44 | Widget build(BuildContext context) {
45 | return Scaffold(
46 | body: Container(
47 | padding: EdgeInsets.all(30),
48 | child: Center(
49 | child: Column(
50 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
51 | children: [
52 | _topItem(),
53 | _bottomItem(),
54 | ],
55 | ),
56 | ),
57 | ),
58 | );
59 | }
60 |
61 | _topItem() {
62 | return Column(
63 | children: [
64 | Padding(
65 | padding: EdgeInsets.fromLTRB(0, 20, 0, 30),
66 | child: Text(
67 | "你可以这样说",
68 | style: TextStyle(fontSize: 16, color: Colors.black54),
69 | ),
70 | ),
71 | Text(
72 | "故宫门票\n背景一日游\n迪士尼乐园",
73 | textAlign: TextAlign.center,
74 | style: TextStyle(fontSize: 15, color: Colors.grey),
75 | ),
76 | Padding(
77 | padding: EdgeInsets.all(20),
78 | child: Text(
79 | speakResult,
80 | style: TextStyle(color: Colors.blue),
81 | ),
82 | ),
83 | ],
84 | );
85 | }
86 |
87 | _speakStart() {
88 | controller.forward();
89 | setState(() {
90 | speakTips = '- 识别中 -';
91 | });
92 | AsrManager.start().then((text) {
93 | if (text != null && text.length > 0) {
94 | setState(() {
95 | speakResult = text;
96 | });
97 | //先关闭页面再跳转
98 | Navigator.pop(context);
99 | NavigatorUtil.push(context, SearchPage(
100 | keyword: speakResult,
101 | ));
102 | }
103 | }).catchError((e){
104 | print("-----" + e.toString());
105 | });
106 | }
107 |
108 | _speakStop() {
109 | setState(() {
110 | speakTips = "长按说话";
111 | });
112 | controller.reset();
113 | controller.stop();
114 | AsrManager.stop();
115 | }
116 |
117 | _bottomItem() {
118 | return FractionallySizedBox(
119 | //宽度撑满屏幕
120 | widthFactor: 1,
121 | child: Stack(
122 | children: [
123 | GestureDetector(
124 | onTapDown: (e) {
125 | _speakStart();
126 | },
127 | onTapUp: (e) {
128 | _speakStop();
129 | },
130 | onTapCancel: () {
131 | _speakStop();
132 | },
133 | child: Center(
134 | child: Column(
135 | children: [
136 | Padding(
137 | padding: EdgeInsets.all(10),
138 | child: Text(
139 | speakTips,
140 | style: TextStyle(color: Colors.blue, fontSize: 12),
141 | ),
142 | ),
143 | Stack(
144 | //为了按钮放大缩小时不改变上面布局的大小
145 | children: [
146 | Container(
147 | height: MIC_SIZE,
148 | width: MIC_SIZE,
149 | ),
150 | Center(
151 | child: AnimatedMic(
152 | animation: animation,
153 | ),
154 | ),
155 | ],
156 | ),
157 | ],
158 | ),
159 | ),
160 | ),
161 | Positioned(
162 | right: 0,
163 | bottom: 20,
164 | child: GestureDetector(
165 | onTap: () {
166 | Navigator.pop(context);
167 | },
168 | child: Icon(
169 | Icons.close,
170 | size: 30,
171 | color: Colors.grey,
172 | ),
173 | ),
174 | ),
175 | ],
176 | ),
177 | );
178 | }
179 | }
180 |
181 | const double MIC_SIZE = 80;
182 |
183 | class AnimatedMic extends AnimatedWidget {
184 | static final _opacityTween = Tween(begin: 1, end: 0.5);
185 | static final _sizeTween = Tween(begin: MIC_SIZE, end: MIC_SIZE - 20);
186 |
187 | AnimatedMic({Key key, Animation animation})
188 | : super(key: key, listenable: animation);
189 |
190 | @override
191 | Widget build(BuildContext context) {
192 | final Animation animation = listenable;
193 | return Opacity(
194 | opacity: _opacityTween.evaluate(animation),
195 | child: Container(
196 | height: _sizeTween.evaluate(animation),
197 | width: _sizeTween.evaluate(animation),
198 | decoration: BoxDecoration(
199 | color: Colors.blue,
200 | borderRadius: BorderRadius.circular(MIC_SIZE / 2),
201 | ),
202 | child: Icon(
203 | Icons.mic,
204 | color: Colors.white,
205 | size: 30,
206 | ),
207 | ),
208 | );
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/lib/pages/travel_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:xiechengwang_app/dao/travel_tab_dao.dart';
3 | import 'package:xiechengwang_app/model/travel_tab_model.dart';
4 | import 'package:xiechengwang_app/pages/travel_tab_page.dart';
5 |
6 | class TravelPage extends StatefulWidget {
7 | @override
8 | _TravelPageState createState() {
9 | // TODO: implement createState
10 | return _TravelPageState();
11 | }
12 | }
13 |
14 | class _TravelPageState extends State
15 | with TickerProviderStateMixin {
16 | TabController _controller;
17 | List tabs = [];
18 | TravelTabModel travelTabModel;
19 |
20 | @override
21 | void initState() {
22 | _controller = TabController(length: 0, vsync: this);
23 | TravelTabDao.fetch().then((TravelTabModel model) {
24 | //解决顶部tab空白问题
25 | _controller = TabController(length: model.tabs.length, vsync: this);
26 | setState(() {
27 | tabs = model.tabs;
28 | travelTabModel = model;
29 | });
30 | }).catchError((e) {
31 | print(e);
32 | });
33 | super.initState();
34 | }
35 |
36 | @override
37 | void dispose() {
38 | _controller.dispose();
39 | super.dispose();
40 | }
41 |
42 | @override
43 | Widget build(BuildContext context) {
44 | return Scaffold(
45 | body: Column(
46 | children: [
47 | Container(
48 | color: Colors.white,
49 | padding: EdgeInsets.only(top: 30),
50 | child: TabBar(
51 | controller: _controller,
52 | isScrollable: true,
53 | labelColor: Colors.black,
54 | labelPadding: EdgeInsets.fromLTRB(20, 0, 10, 5),
55 | indicator: UnderlineTabIndicator(
56 | borderSide: BorderSide(color: Color(0xff2fcfbb), width: 3),
57 | insets: EdgeInsets.only(bottom: 10),
58 | ),
59 | tabs: tabs.map((TravelTab tab) {
60 | return Tab(
61 | text: tab.labelName,
62 | );
63 | }).toList(),
64 | ),
65 | ),
66 | Flexible(
67 | child: TabBarView(
68 | //会有异常 需用Flexible撑开
69 | controller: _controller,
70 | children: tabs.map((TravelTab tab) {
71 | return TravelTabPage(
72 | travelUrl: travelTabModel.url,
73 | groupChannelCode: tab.groupChannelCode,
74 | );
75 | }).toList(),
76 | ),
77 | ),
78 | ],
79 | ),
80 | );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/lib/pages/travel_tab_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
3 | import 'package:xiechengwang_app/dao/travel_dao.dart';
4 | import 'package:xiechengwang_app/model/travel_model.dart';
5 | import 'package:xiechengwang_app/util/navigator_util.dart';
6 | import 'package:xiechengwang_app/widget/loading_container.dart';
7 | import 'package:xiechengwang_app/widget/webview.dart';
8 |
9 | const _TRAVEL_URL =
10 | "https://m.ctrip.com/restapi/soa2/16189/json/searchTripShootListForHomePageV2?_fxpcqlniredt=09031014111431397988&__gw_appid=99999999&__gw_ver=1.0&__gw_from=10650013707&__gw_platform=H5";
11 | const PAGE_SIZE = 10;
12 |
13 | class TravelTabPage extends StatefulWidget {
14 | final String travelUrl;
15 | final String groupChannelCode;
16 |
17 | const TravelTabPage({Key key, this.travelUrl, this.groupChannelCode})
18 | : super(key: key);
19 |
20 | @override
21 | _TravelTabPageState createState() {
22 | // TODO: implement createState
23 | return _TravelTabPageState();
24 | }
25 | }
26 |
27 | class _TravelTabPageState extends State
28 | with AutomaticKeepAliveClientMixin {
29 | List travelItems = [];
30 | int pageIndex = 1;
31 | bool isLoading = true;
32 | ScrollController _scrollController = ScrollController();
33 |
34 | @override
35 | void initState() {
36 | _loadData();
37 | _scrollController.addListener((){
38 | if(_scrollController.position.pixels == _scrollController.position.maxScrollExtent){
39 | _loadData(loadMore: true);
40 | }
41 | });
42 | super.initState();
43 | }
44 | @override
45 | void dispose() {
46 | _scrollController.dispose();
47 | super.dispose();
48 | }
49 | void _loadData({loadMore=false}) {
50 | if(loadMore){
51 | pageIndex ++;
52 | }else{
53 | pageIndex = 1;
54 | }
55 | TravelDao.fetch(widget.travelUrl ?? _TRAVEL_URL, widget.groupChannelCode,
56 | pageIndex, PAGE_SIZE)
57 | .then((model) {
58 | setState(() {
59 | isLoading = false;
60 | List items = _filterItems(model.resultList);
61 | if (items != null) {
62 | travelItems.addAll(items);
63 | } else {
64 | travelItems = items;
65 | }
66 | });
67 | }).catchError((e) {
68 | isLoading = false;
69 | print(e);
70 | });
71 | }
72 |
73 | Future _handleRefresh() async {
74 | _loadData();
75 | return null;
76 | }
77 |
78 | @override
79 | Widget build(BuildContext context) {
80 | return Scaffold(
81 | body: LoadingContainer(
82 | isLoading: isLoading,
83 | child: RefreshIndicator(
84 | onRefresh: _handleRefresh,
85 | child: MediaQuery.removePadding(
86 | context: context,
87 | removeTop: true,
88 | child: StaggeredGridView.countBuilder(
89 | controller: _scrollController,
90 | crossAxisCount: 2,
91 | itemCount: travelItems?.length ?? 0,
92 | itemBuilder: (BuildContext context, int index) =>
93 | _TravelItem(index: index, item: travelItems[index]),
94 | staggeredTileBuilder: (int index) => new StaggeredTile.fit(1),
95 | mainAxisSpacing: 4.0,
96 | crossAxisSpacing: 4.0,
97 | ),
98 | ),
99 | ),
100 | ),
101 | );
102 | }
103 |
104 | @override
105 | bool get wantKeepAlive => true;
106 | }
107 |
108 | List _filterItems(List resultList) {
109 | if (resultList == null) {
110 | return [];
111 | }
112 | List filterItems = [];
113 | resultList.forEach((item) {
114 | if (item.article != null) {
115 | filterItems.add(item);
116 | }
117 | });
118 | return filterItems;
119 | }
120 |
121 | class _TravelItem extends StatelessWidget {
122 | final TravelItem item;
123 | final int index;
124 |
125 | const _TravelItem({Key key, this.item, this.index}) : super(key: key);
126 |
127 | @override
128 | Widget build(BuildContext context) {
129 | return GestureDetector(
130 | onTap: () {
131 | if (item.article.urls != null && item.article.urls.length > 0) {
132 | NavigatorUtil.push(context, WebView(url: item.article.urls[0].h5Url, title: "详情"));
133 | }
134 | },
135 | child: Card(
136 | child: PhysicalModel(
137 | color: Colors.transparent,
138 | clipBehavior: Clip.antiAlias,
139 | borderRadius: BorderRadius.circular(5),
140 | child: Column(
141 | crossAxisAlignment: CrossAxisAlignment.start,
142 | children: [
143 | _itemImage(),
144 | Container(
145 | padding: EdgeInsets.all(4),
146 | child: Text(
147 | item.article.articleTitle,
148 | maxLines: 2,
149 | overflow: TextOverflow.ellipsis,
150 | style: TextStyle(fontSize: 14, color: Colors.black87),
151 | ),
152 | ),
153 | _infoText(),
154 | ],
155 | ),
156 | ),
157 | ),
158 | );
159 | }
160 |
161 | Widget _itemImage() {
162 | return Stack(
163 | children: [
164 | Image.network(item.article.images[0]?.dynamicUrl),
165 | Positioned(
166 | bottom: 8,
167 | left: 8,
168 | child: Container(
169 | padding: EdgeInsets.fromLTRB(5, 1, 5, 1),
170 | decoration: BoxDecoration(
171 | color: Colors.black54, borderRadius: BorderRadius.circular(10)),
172 | child: Row(
173 | children: [
174 | Padding(
175 | padding: EdgeInsets.only(right: 3),
176 | child: Icon(
177 | Icons.location_on,
178 | color: Colors.white,
179 | size: 12,
180 | ),
181 | ),
182 | LimitedBox(
183 | maxWidth: 130,
184 | child: Text(
185 | _poiName(),
186 | maxLines: 1,
187 | overflow: TextOverflow.ellipsis,
188 | style: TextStyle(color: Colors.white, fontSize: 12),
189 | ),
190 | ),
191 | ],
192 | ),
193 | ),
194 | ),
195 | ],
196 | );
197 | }
198 |
199 | Widget _infoText() {
200 | return Container(
201 | padding: EdgeInsets.fromLTRB(6, 0, 6, 10),
202 | child: Row(
203 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
204 | children: [
205 | Row(
206 | children: [
207 | PhysicalModel(
208 | color: Colors.transparent,
209 | clipBehavior: Clip.antiAlias,
210 | borderRadius: BorderRadius.circular(12),
211 | child: Image.network(
212 | item.article.author?.coverImage?.dynamicUrl,
213 | width: 24,
214 | height: 24,
215 | ),
216 | ),
217 | Container(
218 | padding: EdgeInsets.all(5),
219 | width: 90,
220 | child: Text(
221 | item.article.author?.nickName,
222 | maxLines: 1,
223 | overflow: TextOverflow.ellipsis,
224 | style: TextStyle(fontSize: 12),
225 | ),
226 | )
227 | ],
228 | ),
229 | Row(
230 | children: [
231 | Icon(
232 | Icons.thumb_up,
233 | size: 14,
234 | color: Colors.grey,
235 | ),
236 | Padding(
237 | padding: EdgeInsets.only(left: 3),
238 | child: Text(
239 | item.article.likeCount.toString(),
240 | style: TextStyle(fontSize: 10),
241 | ),
242 | ),
243 | ],
244 | ),
245 | ],
246 | ),
247 | );
248 | }
249 |
250 | String _poiName() {
251 | return item.article.pois == null || item.article.pois.length == 0
252 | ? "未知"
253 | : item.article.pois[0].poiName ?? "未知";
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/lib/plugin/asr_manager.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 |
3 | class AsrManager {
4 | static const MethodChannel _channel = const MethodChannel("asr_plugin");
5 |
6 | //开始录音
7 | static Future start({Map params}) async {
8 | return await _channel.invokeMethod("start", params ?? {});
9 | }
10 |
11 | //停止录音
12 | static Future stop() async {
13 | return await _channel.invokeMethod("stop");
14 | }
15 |
16 | //取消录音
17 | static Future cancel() async {
18 | return await _channel.invokeMethod("cancel");
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/util/navigator_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class NavigatorUtil {
5 | ///跳转到指定页面
6 | static push(BuildContext context, Widget page) {
7 | Navigator.push(context, MaterialPageRoute(builder: (context) => page));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/widget/grid_nav.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:xiechengwang_app/model/common_model.dart';
3 | import 'package:xiechengwang_app/model/grid_nav_model.dart';
4 | import 'package:xiechengwang_app/util/navigator_util.dart';
5 | import 'package:xiechengwang_app/widget/webview.dart';
6 |
7 | //网格布局
8 | class GridNav extends StatelessWidget {
9 | final GridNavModel gridNavModel;
10 |
11 | const GridNav({Key key, @required this.gridNavModel}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return PhysicalModel(
16 | //圆角彩蛋
17 | color: Colors.transparent,
18 | borderRadius: BorderRadius.circular(6),
19 | clipBehavior: Clip.antiAlias,
20 | child: Column(
21 | children: _gridNavItems(context),
22 | ),
23 | );
24 | }
25 |
26 | _gridNavItems(BuildContext context) {
27 | List items = [];
28 | if (gridNavModel == null) {
29 | return items;
30 | }
31 | if (gridNavModel.hotel != null) {
32 | items.add(_gridNavItem(context, gridNavModel.hotel, true));
33 | }
34 | if (gridNavModel.flight != null) {
35 | items.add(_gridNavItem(context, gridNavModel.flight, false));
36 | }
37 | if (gridNavModel.travel != null) {
38 | items.add(_gridNavItem(context, gridNavModel.travel, false));
39 | }
40 | return items;
41 | }
42 |
43 | //每行卡片组成 左 main item + 中 item1 + 右 item2
44 | _gridNavItem(BuildContext context, GridNavItem gridNavItem, bool first) {
45 | List items = [];
46 |
47 | items.add(_mainItem(context, gridNavItem.mainItem));
48 | items.add(_doubleItem(context, gridNavItem.item1, gridNavItem.item2));
49 | items.add(_doubleItem(context, gridNavItem.item3, gridNavItem.item4));
50 | List expandItems = [];
51 | items.forEach((item) {
52 | expandItems.add(Expanded(
53 | child: item,
54 | flex: 1,
55 | ));
56 | });
57 | Color startColor = Color(int.parse("0xff" + gridNavItem.startColor));
58 | Color endColor = Color(int.parse("0xff" + gridNavItem.endColor));
59 | return Container(
60 | height: 88,
61 | margin: first ? null : EdgeInsets.only(top: 3),
62 | decoration: BoxDecoration(
63 | //线性渐变
64 | gradient: LinearGradient(colors: [startColor, endColor])),
65 | child: Row(
66 | children: expandItems,
67 | ),
68 | );
69 | }
70 |
71 | //
72 | _mainItem(BuildContext context, CommonModel model) {
73 | return _wrapGesture(
74 | context,
75 | Stack(
76 | alignment: Alignment.topCenter,
77 | children: [
78 | Image.network(
79 | model.icon,
80 | fit: BoxFit.contain,
81 | height: 88,
82 | width: 121,
83 | alignment: AlignmentDirectional.bottomEnd,
84 | ),
85 | Container(
86 | margin: EdgeInsets.only(top: 12),
87 | child: Text(
88 | model.title,
89 | style: TextStyle(fontSize: 14, color: Colors.white),
90 | ),
91 | ),
92 | ],
93 | ),
94 | model);
95 | }
96 |
97 | _doubleItem(
98 | BuildContext context,
99 | CommonModel topItem,
100 | CommonModel bottomItem,
101 | ) {
102 | return Column(
103 | children: [
104 | Expanded(
105 | //高 展开
106 | child: _item(context, topItem, true),
107 | ),
108 | Expanded(
109 | child: _item(context, bottomItem, false),
110 | ),
111 | ],
112 | );
113 | }
114 |
115 | _item(BuildContext context, CommonModel item, bool first) {
116 | BorderSide borderSide = BorderSide(width: 0.8, color: Colors.white);
117 | return FractionallySizedBox(
118 | widthFactor: 1,
119 | child: Container(
120 | decoration: BoxDecoration(
121 | border: Border(
122 | left: borderSide,
123 | bottom: first ? borderSide : BorderSide.none, //第一个底部有分割线
124 | )),
125 | child: _wrapGesture(
126 | context,
127 | Center(
128 | child: Text(
129 | item.title,
130 | textAlign: TextAlign.center,
131 | style: TextStyle(fontSize: 14, color: Colors.white),
132 | ),
133 | ),
134 | item)),
135 | );
136 | }
137 |
138 | _wrapGesture(BuildContext context, Widget widget, CommonModel model) {
139 | return GestureDetector(
140 | onTap: () {
141 | NavigatorUtil.push(
142 | context,
143 | WebView(
144 | url: model.url,
145 | statusBarColor: model.statusBarColor,
146 | hideAppBar: model.hideAppBar,
147 | ));
148 | },
149 | child: widget,
150 | );
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/lib/widget/loading_container.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | //加载进度条
6 | class LoadingContainer extends StatelessWidget{
7 | final Widget child;
8 | final bool isLoading;
9 | final bool cover;//是否放在顶层
10 |
11 | const LoadingContainer({Key key,@required this.child, @required this.isLoading, this.cover = false}):super(key:key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | // TODO: implement build
16 | return !cover ? !isLoading ?child : _loadingView : Stack(
17 | children: [
18 | child,
19 | isLoading ?_loadingView : null,
20 | ],
21 | );
22 | }
23 |
24 | Widget get _loadingView {
25 | return Center(
26 | child: CircularProgressIndicator(),
27 | );
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/lib/widget/local_nav.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:xiechengwang_app/model/common_model.dart';
5 | import 'package:xiechengwang_app/util/navigator_util.dart';
6 | import 'package:xiechengwang_app/widget/webview.dart';
7 |
8 | class LocalNav extends StatelessWidget{
9 | final List localNavList;
10 |
11 | const LocalNav({Key key,@required this.localNavList}):super(key:key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | // TODO: implement build
16 | return Container(
17 | height: 64,
18 | decoration: BoxDecoration(
19 | color: Colors.white,
20 | borderRadius: BorderRadius.all(Radius.circular(6)),
21 | ),
22 | child: Padding(
23 | padding: EdgeInsets.all(7),
24 | child: _items(context),
25 | ),
26 | );
27 | }
28 |
29 | _items(BuildContext context){
30 | if(localNavList == null){
31 | return null;
32 | }
33 | List items = [];
34 | localNavList.forEach((model)=> items.add(_item(context, model)));
35 |
36 | return Row(
37 | mainAxisAlignment: MainAxisAlignment.spaceAround,//平均排列
38 | children:items,
39 | );
40 | }
41 | Widget _item(BuildContext context,CommonModel model){
42 | return GestureDetector(
43 | onTap: (){
44 | NavigatorUtil.push(context, WebView(url:model.url,statusBarColor: model.statusBarColor,hideAppBar: model.hideAppBar,));
45 | },
46 | child: Column(
47 | children: [
48 | Image.network(
49 | model.icon,
50 | width: 32,
51 | height: 32,
52 | ),
53 | Text(
54 | model.title,
55 | style: TextStyle(fontSize: 12),
56 | )
57 | ],
58 | ),
59 | );
60 | }
61 | }
--------------------------------------------------------------------------------
/lib/widget/sales_box.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:xiechengwang_app/model/common_model.dart';
4 | import 'package:xiechengwang_app/model/sales_box_model.dart';
5 | import 'package:xiechengwang_app/util/navigator_util.dart';
6 | import 'package:xiechengwang_app/widget/webview.dart';
7 |
8 | //底部卡片入口
9 | class SalesBox extends StatelessWidget {
10 | final SalesBoxModel salesBox;
11 |
12 | const SalesBox({Key key, @required this.salesBox}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Container(
17 | decoration: BoxDecoration(
18 | color: Colors.white,
19 | ),
20 | child: _items(context),
21 | );
22 | }
23 |
24 | _items(BuildContext context) {
25 | if (salesBox == null) {
26 | return null;
27 | }
28 | List items = [];
29 | items.add(_doubleItem(context,salesBox.bigCard1,salesBox.bigCard2,true,false));
30 | items.add(_doubleItem(context,salesBox.smallCard1,salesBox.smallCard2,false,false));
31 | items.add(_doubleItem(context,salesBox.smallCard3,salesBox.smallCard4,false,true));
32 |
33 |
34 | return Column(
35 | children: [
36 | Container(
37 | height: 44,
38 | margin: EdgeInsets.only(left: 10),
39 | decoration: BoxDecoration(
40 | border: Border(bottom: BorderSide(width: 1,color: Color(0xfff2f2))), //下划线
41 | ),
42 | child: Row(
43 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
44 | children: [
45 | Image.network(salesBox.icon,height: 15,fit: BoxFit.fill,),
46 | Container(
47 | padding: EdgeInsets.fromLTRB(10,1,8,1),
48 | margin: EdgeInsets.only(right: 7),
49 | decoration: BoxDecoration(
50 | borderRadius: BorderRadius.circular(12),
51 | gradient: LinearGradient(
52 | colors: [Color(0xffff4e63),Color(0xffff6cc9)],
53 | begin: Alignment.centerLeft,
54 | end: Alignment.centerRight
55 | )
56 | ),
57 | child: GestureDetector(
58 | onTap: (){
59 | NavigatorUtil.push(context, WebView(url: salesBox.moreUrl,title: "更多活动",));
60 | },
61 | child: Text('获取更多福利 >',style: TextStyle(color: Colors.white,fontSize: 12),),
62 | ),
63 | )
64 | ],
65 | ),
66 | ),
67 |
68 | Row(
69 | mainAxisAlignment: MainAxisAlignment.center,
70 | children: items.sublist(0,1),
71 | ),
72 | Row(
73 | mainAxisAlignment: MainAxisAlignment.center,
74 | children: items.sublist(1,2),
75 | ),
76 | Row(mainAxisAlignment: MainAxisAlignment.center,
77 | children: items.sublist(2,3),
78 | ),
79 |
80 | ],
81 | );
82 | }
83 |
84 | _doubleItem(BuildContext context,CommonModel leftCard,CommonModel rightCard,bool big,bool last){
85 | return Row(
86 | mainAxisAlignment: MainAxisAlignment.spaceAround,
87 | children: [
88 | _item(context, leftCard,big,true,last),
89 | _item(context, rightCard,big,false,last),
90 | ],
91 | );
92 | }
93 |
94 | Widget _item(BuildContext context, CommonModel model,bool big,bool left,bool last) {
95 | BorderSide borderSide = BorderSide(width: 0.8,color: Color(0xfff2f2));
96 | return GestureDetector(
97 | onTap: () {
98 | NavigatorUtil.push(context, WebView(
99 | url: model.url,
100 | statusBarColor: model.statusBarColor,
101 | hideAppBar: model.hideAppBar,
102 | ));
103 | },
104 | child: Container(
105 | decoration: BoxDecoration(
106 | border: Border(right: left ? borderSide :BorderSide.none,
107 | bottom: last ? BorderSide.none : borderSide),
108 |
109 | ),
110 | child: Image.network(
111 | model.icon,
112 | fit: BoxFit.fill,
113 | width: MediaQuery.of(context).size.width / 2 - 10,
114 | height: big ? 129 : 80,
115 | ),
116 | ),
117 |
118 | );
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/lib/widget/search_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | enum SearchBarType { home, normal, homeLight }
5 |
6 | class SearchBar extends StatefulWidget {
7 | final bool enabled;
8 | final bool hideLeft;
9 | final SearchBarType searchBarType;
10 | final String hint;
11 | final String defaultText;
12 | final void Function() leftButtonClick;
13 | final void Function() rightButtonClick;
14 | final void Function() speakClick;
15 | final void Function() inputBoxClick;
16 | final ValueChanged onChanged;
17 |
18 | const SearchBar(
19 | {Key key,
20 | this.enabled = true,
21 | this.hideLeft,
22 | this.searchBarType = SearchBarType.normal,
23 | this.hint,
24 | this.defaultText,
25 | this.leftButtonClick,
26 | this.rightButtonClick,
27 | this.speakClick,
28 | this.inputBoxClick,
29 | this.onChanged})
30 | : super(key: key);
31 |
32 | @override
33 | _SearchBarState createState() {
34 | return _SearchBarState();
35 | }
36 | }
37 |
38 | class _SearchBarState extends State {
39 | bool showClear = false;
40 | final TextEditingController _controller = TextEditingController();
41 |
42 | @override
43 | void initState() {
44 | super.initState();
45 | if (widget.defaultText != null) {
46 | setState(() {
47 | _controller.text = widget.defaultText;
48 | });
49 | }
50 | }
51 |
52 | @override
53 | Widget build(BuildContext context) {
54 | return widget.searchBarType == SearchBarType.normal
55 | ? _genNormalSearch()
56 | : _genHomeSearch();
57 | }
58 |
59 | _genNormalSearch() {
60 | return Container(
61 | child: Row(
62 | children: [
63 | _wrapTap(
64 | Container(
65 | padding: EdgeInsets.fromLTRB(6, 5, 6, 5),
66 | child: widget?.hideLeft ?? false
67 | ? null
68 | : Icon(
69 | Icons.arrow_back_ios,
70 | color: Colors.grey,
71 | size: 26,
72 | ),
73 | ),
74 | widget.leftButtonClick),
75 | Expanded(
76 | flex: 1,
77 | child: _inputBox(),
78 | ),
79 | _wrapTap(
80 | Container(
81 | padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
82 | child: Text(
83 | '搜索',
84 | style: TextStyle(color: Colors.blue, fontSize: 17),
85 | ),
86 | ),
87 | widget.rightButtonClick),
88 | ],
89 | ),
90 | );
91 | }
92 |
93 | _inputBox() {
94 | Color inputBoxColor;
95 | if (widget.searchBarType == SearchBarType.home) {
96 | inputBoxColor = Colors.white;
97 | } else {
98 | inputBoxColor = Color(int.parse('0xffEDEDED'));
99 | }
100 | return Container(
101 | height: 30,
102 | padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
103 | decoration: BoxDecoration(
104 | color: inputBoxColor,
105 | borderRadius: BorderRadius.circular(widget.searchBarType == SearchBarType.normal ? 5 : 15),
106 | ),
107 | child: Row(
108 | children: [
109 | Icon(
110 | Icons.search,
111 | size: 20,
112 | color: widget.searchBarType == SearchBarType.normal
113 | ? Color(0xffA9A9A9)
114 | : Colors.blue,
115 | ),
116 | Expanded(
117 | flex: 1,
118 | child: widget.searchBarType == SearchBarType.normal
119 | ? TextField(
120 | controller: _controller,
121 | onChanged: _onChanged,
122 | autofocus: true,
123 | style: TextStyle(
124 | fontSize: 18.0,
125 | color: Colors.black,
126 | fontWeight: FontWeight.w300),
127 | //输入文本的样式
128 | decoration: InputDecoration(
129 | contentPadding: EdgeInsets.fromLTRB(5, 0, 5, 0),
130 | border: InputBorder.none,
131 | hintText: widget.hint ?? "",
132 | hintStyle: TextStyle(fontSize: 15),
133 | ),
134 | )
135 | : _wrapTap(
136 | Container(
137 | child: Text(
138 | widget.defaultText,
139 | style: TextStyle(fontSize: 13, color: Colors.grey),
140 | ),
141 | ),
142 | widget.inputBoxClick),
143 | ),
144 | !showClear ? _wrapTap(Icon(Icons.mic,size: 22,color: widget.searchBarType == SearchBarType.normal ? Colors.blue:Colors.grey,), widget.speakClick)
145 | : _wrapTap(Icon(Icons.clear,size: 22,color: Colors.grey,), (){
146 | setState(() {
147 | _controller.clear();
148 | });
149 | _onChanged("");
150 | })
151 | ],
152 | ),
153 | );
154 | }
155 |
156 | _genHomeSearch() {
157 | return Container(
158 | child: Row(
159 | children: [
160 | _wrapTap(
161 | Container(
162 | padding: EdgeInsets.fromLTRB(6, 5, 5, 5),
163 | child:Row(
164 | children: [
165 | Text('上海',style: TextStyle(color: _homeFontColor(),fontSize: 14),),
166 | Icon(Icons.expand_more,color: _homeFontColor(),size: 22,)
167 | ],
168 | ),
169 | ),
170 | widget.leftButtonClick),
171 | Expanded(
172 | flex: 1,
173 | child: _inputBox(),
174 | ),
175 | _wrapTap(
176 | Container(
177 | padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
178 | child: Icon(Icons.comment,color: _homeFontColor(),size: 26,)
179 | ),
180 | widget.rightButtonClick),
181 | ],
182 | ),
183 | );
184 | }
185 |
186 | _wrapTap(Widget child, void Function() callback) {
187 | return GestureDetector(
188 | onTap: () {
189 | if (callback != null) {
190 | callback();
191 | }
192 | },
193 | child: child,
194 | );
195 | }
196 |
197 | _onChanged(String text) {
198 | if (text.length > 0) {
199 | setState(() {
200 | showClear = true;
201 | });
202 | } else {
203 | setState(() {
204 | showClear = false;
205 | });
206 | }
207 | if (widget.onChanged != null) {
208 | widget.onChanged(text);
209 | }
210 | }
211 | _homeFontColor(){
212 | return widget.searchBarType == SearchBarType.homeLight ? Colors.black54 : Colors.white;
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/lib/widget/sub_nav.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:xiechengwang_app/model/common_model.dart';
4 | import 'package:xiechengwang_app/util/navigator_util.dart';
5 | import 'package:xiechengwang_app/widget/webview.dart';
6 |
7 | class SubNav extends StatelessWidget {
8 | final List subNavList;
9 |
10 | const SubNav({Key key, @required this.subNavList}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | // TODO: implement build
15 | return Container(
16 | decoration: BoxDecoration(
17 | color: Colors.white,
18 | borderRadius: BorderRadius.all(Radius.circular(6)),
19 | ),
20 | child: Padding(
21 | padding: EdgeInsets.all(7),
22 | child: _items(context),
23 | ),
24 | );
25 | }
26 |
27 | _items(BuildContext context) {
28 | if (subNavList == null) {
29 | return null;
30 | }
31 | List items = [];
32 | subNavList.forEach((model) => items.add(_item(context, model)));
33 |
34 | int separate = (subNavList.length / 2 + 0.5).toInt();
35 |
36 | return Column(
37 | children: [
38 | Row(
39 | mainAxisAlignment: MainAxisAlignment.spaceAround, //平均排列
40 | children: items.sublist(0, separate),
41 | ),
42 | Padding(
43 | padding: EdgeInsets.only(top: 10),
44 | child: Row(
45 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
46 | children: items.sublist(separate, subNavList.length),
47 | ),
48 | ),
49 | ],
50 | );
51 | }
52 |
53 | Widget _item(BuildContext context, CommonModel model) {
54 | return Expanded(
55 | flex: 1,
56 | child: GestureDetector(
57 | onTap: () {
58 | NavigatorUtil.push(context, WebView(
59 | url: model.url,
60 | statusBarColor: model.statusBarColor,
61 | hideAppBar: model.hideAppBar,
62 | ));
63 | },
64 | child: Column(
65 | children: [
66 | Image.network(
67 | model.icon,
68 | width: 18,
69 | height: 18,
70 | ),
71 | Padding(
72 | padding: EdgeInsets.only(top: 3),
73 | child: Text(
74 | model.title,
75 | style: TextStyle(fontSize: 12),
76 | )),
77 | ],
78 | ),
79 | ),
80 | );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/lib/widget/webview.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
6 |
7 | const CATCH_URLS = ['m.ctrip.com/','m.ctrip.com/html5/','m.ctrip.com/html5'];
8 |
9 | class WebView extends StatefulWidget {
10 | final String url;
11 | final String statusBarColor;
12 | final String title;
13 | final bool hideAppBar;
14 | final bool backForbid;
15 |
16 | WebView(
17 | {this.url,
18 | this.statusBarColor,
19 | this.title,
20 | this.hideAppBar,
21 | this.backForbid = false});
22 |
23 | @override
24 | State createState() {
25 | // TODO: implement createState
26 | return _WebViewState();
27 | }
28 | }
29 |
30 | class _WebViewState extends State {
31 | final webViewReference = FlutterWebviewPlugin();
32 | StreamSubscription _onUrlChanged;
33 | StreamSubscription _onStateChanged;
34 | StreamSubscription _onHttpError;
35 |
36 | bool exiting = false;
37 | @override
38 | void initState() {
39 | super.initState();
40 | webViewReference.close();
41 | _onUrlChanged = webViewReference.onUrlChanged.listen((String url) {});
42 | _onStateChanged =
43 | webViewReference.onStateChanged.listen((WebViewStateChanged state) {
44 | switch (state.type) {
45 | case WebViewState.startLoad:
46 | //防止返回到上一主页 携程首页
47 | if(_isToMain(state.url) && !exiting){
48 | if(widget.backForbid){
49 | //禁止返回到主页面
50 | webViewReference.launch(widget.url);
51 | }else{
52 | Navigator.pop(context);
53 | exiting = true;
54 | }
55 | }
56 | break;
57 | default:
58 | break;
59 | }
60 | });
61 | _onHttpError =
62 | webViewReference.onHttpError.listen((WebViewHttpError error) {
63 | print(error.toString());
64 | });
65 | }
66 |
67 | _isToMain(String url){
68 | bool contain = false;
69 | for(final value in CATCH_URLS){
70 | if(url?.endsWith(value) ?? false){
71 | contain = true;
72 | break;
73 | }
74 | }
75 | return contain;
76 | }
77 | @override
78 | void dispose() {
79 | _onHttpError.cancel();
80 | _onStateChanged.cancel();
81 | _onUrlChanged.cancel(); //取消注册监听
82 | webViewReference.dispose();
83 | super.dispose();
84 | }
85 |
86 | @override
87 | Widget build(BuildContext context) {
88 | String statusBarColorStr = widget.statusBarColor ?? "ffffff";
89 | Color backButtonColor;
90 | if(statusBarColorStr == "ffffff"){
91 | backButtonColor = Colors.black;
92 | }else{
93 | backButtonColor = Colors.white;
94 | }
95 | return Scaffold(
96 | body: Column(
97 | children: [
98 | _appBar(Color(int.parse("0xff"+statusBarColorStr)),backButtonColor),
99 | Expanded(child: WebviewScaffold(
100 | url: widget.url,
101 | withZoom: true,
102 | withLocalStorage: true,
103 | hidden: true, //有bug,设置隐藏后,initialChild不会显示
104 | initialChild: Container(
105 | color: Colors.white,
106 | child: Center(
107 | child: Text("Waiting...."),
108 | ),
109 | ),
110 | )),
111 | ],
112 | ),
113 | );
114 | }
115 |
116 | _appBar(Color backgroundColor, Color backButtonColor) {
117 | if (widget.hideAppBar ?? false) {
118 | return Container(
119 | padding: EdgeInsets.fromLTRB(0, 40, 0, 10),//例如IphoneX 顶部刘海导致的问题
120 | color: backgroundColor,
121 | height: 30,
122 | );
123 | }
124 | return Container(
125 | padding: EdgeInsets.fromLTRB(0, 40, 0, 10),//例如IphoneX 顶部刘海导致的问题
126 | color: backgroundColor,
127 | child: FractionallySizedBox(
128 | //撑满屏幕宽度
129 | widthFactor: 1,
130 | child: Stack(
131 | children: [
132 | GestureDetector(
133 | onTap: (){
134 | Navigator.pop(context);
135 | },
136 | child: Container(
137 | margin: EdgeInsets.only(left: 10),
138 | child: Icon(
139 | Icons.close,
140 | color: backButtonColor,
141 | size: 26,
142 | ),
143 | ),
144 | ),
145 | Positioned(
146 | left: 0,
147 | right: 0,
148 | child: Center(
149 | child: Text(
150 | widget.title ?? "",
151 | style: TextStyle(color: backButtonColor,fontSize: 20),
152 | ),
153 | ),
154 | )
155 | ],
156 | ),
157 | ),
158 | );
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | url: "https://pub.flutter-io.cn"
9 | source: hosted
10 | version: "2.0.10"
11 | args:
12 | dependency: transitive
13 | description:
14 | name: args
15 | url: "https://pub.flutter-io.cn"
16 | source: hosted
17 | version: "1.5.2"
18 | async:
19 | dependency: transitive
20 | description:
21 | name: async
22 | url: "https://pub.flutter-io.cn"
23 | source: hosted
24 | version: "2.3.0"
25 | boolean_selector:
26 | dependency: transitive
27 | description:
28 | name: boolean_selector
29 | url: "https://pub.flutter-io.cn"
30 | source: hosted
31 | version: "1.0.5"
32 | charcode:
33 | dependency: transitive
34 | description:
35 | name: charcode
36 | url: "https://pub.flutter-io.cn"
37 | source: hosted
38 | version: "1.1.2"
39 | collection:
40 | dependency: transitive
41 | description:
42 | name: collection
43 | url: "https://pub.flutter-io.cn"
44 | source: hosted
45 | version: "1.14.11"
46 | convert:
47 | dependency: transitive
48 | description:
49 | name: convert
50 | url: "https://pub.flutter-io.cn"
51 | source: hosted
52 | version: "2.1.1"
53 | crypto:
54 | dependency: transitive
55 | description:
56 | name: crypto
57 | url: "https://pub.flutter-io.cn"
58 | source: hosted
59 | version: "2.1.3"
60 | cupertino_icons:
61 | dependency: "direct main"
62 | description:
63 | name: cupertino_icons
64 | url: "https://pub.flutter-io.cn"
65 | source: hosted
66 | version: "0.1.3"
67 | flutter:
68 | dependency: "direct main"
69 | description: flutter
70 | source: sdk
71 | version: "0.0.0"
72 | flutter_page_indicator:
73 | dependency: transitive
74 | description:
75 | name: flutter_page_indicator
76 | url: "https://pub.flutter-io.cn"
77 | source: hosted
78 | version: "0.0.3"
79 | flutter_splash_screen:
80 | dependency: "direct main"
81 | description:
82 | name: flutter_splash_screen
83 | url: "https://pub.flutter-io.cn"
84 | source: hosted
85 | version: "0.1.0"
86 | flutter_staggered_grid_view:
87 | dependency: "direct main"
88 | description:
89 | name: flutter_staggered_grid_view
90 | url: "https://pub.flutter-io.cn"
91 | source: hosted
92 | version: "0.3.0"
93 | flutter_swiper:
94 | dependency: "direct main"
95 | description:
96 | name: flutter_swiper
97 | url: "https://pub.flutter-io.cn"
98 | source: hosted
99 | version: "1.1.6"
100 | flutter_test:
101 | dependency: "direct dev"
102 | description: flutter
103 | source: sdk
104 | version: "0.0.0"
105 | flutter_webview_plugin:
106 | dependency: "direct main"
107 | description:
108 | name: flutter_webview_plugin
109 | url: "https://pub.flutter-io.cn"
110 | source: hosted
111 | version: "0.3.10+1"
112 | http:
113 | dependency: "direct main"
114 | description:
115 | name: http
116 | url: "https://pub.flutter-io.cn"
117 | source: hosted
118 | version: "0.12.0+4"
119 | http_parser:
120 | dependency: transitive
121 | description:
122 | name: http_parser
123 | url: "https://pub.flutter-io.cn"
124 | source: hosted
125 | version: "3.1.3"
126 | image:
127 | dependency: transitive
128 | description:
129 | name: image
130 | url: "https://pub.flutter-io.cn"
131 | source: hosted
132 | version: "2.1.4"
133 | matcher:
134 | dependency: transitive
135 | description:
136 | name: matcher
137 | url: "https://pub.flutter-io.cn"
138 | source: hosted
139 | version: "0.12.5"
140 | meta:
141 | dependency: transitive
142 | description:
143 | name: meta
144 | url: "https://pub.flutter-io.cn"
145 | source: hosted
146 | version: "1.1.7"
147 | path:
148 | dependency: transitive
149 | description:
150 | name: path
151 | url: "https://pub.flutter-io.cn"
152 | source: hosted
153 | version: "1.6.4"
154 | pedantic:
155 | dependency: transitive
156 | description:
157 | name: pedantic
158 | url: "https://pub.flutter-io.cn"
159 | source: hosted
160 | version: "1.8.0+1"
161 | petitparser:
162 | dependency: transitive
163 | description:
164 | name: petitparser
165 | url: "https://pub.flutter-io.cn"
166 | source: hosted
167 | version: "2.4.0"
168 | quiver:
169 | dependency: transitive
170 | description:
171 | name: quiver
172 | url: "https://pub.flutter-io.cn"
173 | source: hosted
174 | version: "2.0.5"
175 | sky_engine:
176 | dependency: transitive
177 | description: flutter
178 | source: sdk
179 | version: "0.0.99"
180 | source_span:
181 | dependency: transitive
182 | description:
183 | name: source_span
184 | url: "https://pub.flutter-io.cn"
185 | source: hosted
186 | version: "1.5.5"
187 | stack_trace:
188 | dependency: transitive
189 | description:
190 | name: stack_trace
191 | url: "https://pub.flutter-io.cn"
192 | source: hosted
193 | version: "1.9.3"
194 | stream_channel:
195 | dependency: transitive
196 | description:
197 | name: stream_channel
198 | url: "https://pub.flutter-io.cn"
199 | source: hosted
200 | version: "2.0.0"
201 | string_scanner:
202 | dependency: transitive
203 | description:
204 | name: string_scanner
205 | url: "https://pub.flutter-io.cn"
206 | source: hosted
207 | version: "1.0.5"
208 | term_glyph:
209 | dependency: transitive
210 | description:
211 | name: term_glyph
212 | url: "https://pub.flutter-io.cn"
213 | source: hosted
214 | version: "1.1.0"
215 | test_api:
216 | dependency: transitive
217 | description:
218 | name: test_api
219 | url: "https://pub.flutter-io.cn"
220 | source: hosted
221 | version: "0.2.5"
222 | transformer_page_view:
223 | dependency: transitive
224 | description:
225 | name: transformer_page_view
226 | url: "https://pub.flutter-io.cn"
227 | source: hosted
228 | version: "0.1.6"
229 | typed_data:
230 | dependency: transitive
231 | description:
232 | name: typed_data
233 | url: "https://pub.flutter-io.cn"
234 | source: hosted
235 | version: "1.1.6"
236 | vector_math:
237 | dependency: transitive
238 | description:
239 | name: vector_math
240 | url: "https://pub.flutter-io.cn"
241 | source: hosted
242 | version: "2.0.8"
243 | xml:
244 | dependency: transitive
245 | description:
246 | name: xml
247 | url: "https://pub.flutter-io.cn"
248 | source: hosted
249 | version: "3.5.0"
250 | sdks:
251 | dart: ">=2.4.0 <3.0.0"
252 | flutter: ">=1.6.0 <3.0.0"
253 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: xiechengwang_app
2 | description: A new Flutter application.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.0+1
15 |
16 | environment:
17 | sdk: ">=2.1.0 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 |
23 | # The following adds the Cupertino Icons font to your application.
24 | # Use with the CupertinoIcons class for iOS style icons.
25 | cupertino_icons: ^0.1.2
26 | flutter_swiper: ^1.1.4
27 | http: ^0.12.0+4
28 | flutter_webview_plugin: ^0.3.10+1
29 | flutter_staggered_grid_view: ^0.3.0
30 | flutter_splash_screen: ^0.1.0
31 |
32 | dev_dependencies:
33 | flutter_test:
34 | sdk: flutter
35 |
36 |
37 | # For information on the generic Dart part of this file, see the
38 | # following page: https://dart.dev/tools/pub/pubspec
39 |
40 | # The following section is specific to Flutter.
41 | flutter:
42 |
43 | # The following line ensures that the Material Icons font is
44 | # included with your application, so that you can use the icons in
45 | # the material Icons class.
46 | uses-material-design: true
47 |
48 | # To add assets to your application, add an assets section, like this:
49 | assets:
50 | - images/type_channeltrain.png
51 | - images/type_channellgs.png
52 | - images/type_channelplane.png
53 | - images/type_channelgroup.png
54 | - images/type_cruise.png
55 | - images/type_district.png
56 | - images/type_food.png
57 | - images/type_hotel.png
58 | - images/type_huodong.png
59 | - images/type_shop.png
60 | - images/type_sight.png
61 | - images/type_ticket.png
62 | - images/type_travelgroup.png
63 | # - images/a_dot_burr.jpeg
64 | # - images/a_dot_ham.jpeg
65 |
66 | # An image asset can refer to one or more resolution-specific "variants", see
67 | # https://flutter.dev/assets-and-images/#resolution-aware.
68 |
69 | # For details regarding adding assets from package dependencies, see
70 | # https://flutter.dev/assets-and-images/#from-packages
71 |
72 | # To add custom fonts to your application, add a fonts section here,
73 | # in this "flutter" section. Each entry in this list should have a
74 | # "family" key with the font family name, and a "fonts" key with a
75 | # list giving the asset and other descriptors for the font. For
76 | # example:
77 | # fonts:
78 | # - family: Schyler
79 | # fonts:
80 | # - asset: fonts/Schyler-Regular.ttf
81 | # - asset: fonts/Schyler-Italic.ttf
82 | # style: italic
83 | # - family: Trajan Pro
84 | # fonts:
85 | # - asset: fonts/TrajanPro.ttf
86 | # - asset: fonts/TrajanPro_Bold.ttf
87 | # weight: 700
88 | #
89 | # For details regarding fonts from package dependencies,
90 | # see https://flutter.dev/custom-fonts/#from-packages
91 |
--------------------------------------------------------------------------------
/screenshot/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/1.png
--------------------------------------------------------------------------------
/screenshot/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/2.png
--------------------------------------------------------------------------------
/screenshot/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/3.png
--------------------------------------------------------------------------------
/screenshot/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/4.png
--------------------------------------------------------------------------------
/screenshot/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/5.png
--------------------------------------------------------------------------------
/screenshot/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/6.png
--------------------------------------------------------------------------------
/screenshot/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/7.png
--------------------------------------------------------------------------------
/screenshot/alt_1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/alt_1.PNG
--------------------------------------------------------------------------------
/screenshot/alt_2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/alt_2.PNG
--------------------------------------------------------------------------------
/screenshot/alt_3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/alt_3.PNG
--------------------------------------------------------------------------------
/screenshot/alt_4.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/alt_4.PNG
--------------------------------------------------------------------------------
/screenshot/alt_5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/alt_5.PNG
--------------------------------------------------------------------------------
/screenshot/alt_6.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/alt_6.PNG
--------------------------------------------------------------------------------
/screenshot/alt_7.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/alt_7.PNG
--------------------------------------------------------------------------------
/screenshot/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeOver2015/xiechengwang_app/2bd9351a077456201480db0a9c11e279ec2d5d5a/screenshot/download.png
--------------------------------------------------------------------------------
/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 | import 'package:xiechengwang_app/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------