├── lib ├── home │ ├── page │ │ ├── database │ │ │ ├── dbpojo.dart │ │ │ └── friend.dart │ │ ├── camera │ │ │ ├── camera_pojo.dart │ │ │ ├── example_camera.dart │ │ │ ├── identify_qrcode.dart │ │ │ └── identify_face.dart │ │ ├── dialog │ │ │ └── dialogdemo.dart │ │ ├── home │ │ │ └── home.dart │ │ └── webview │ │ │ └── mywebview.dart │ └── pojo │ │ └── menu.dart ├── fast │ ├── constants │ │ ├── user.dart │ │ ├── database.dart │ │ └── constant.dart │ ├── utils │ │ ├── callback.dart │ │ ├── app.dart │ │ ├── MethodChannelUtils.dart │ │ ├── empty.dart │ │ ├── datetime.dart │ │ ├── permission.dart │ │ ├── sql.dart │ │ ├── value.dart │ │ ├── shared_preferences.dart │ │ ├── provider.dart │ │ ├── style.dart │ │ └── dialog.dart │ ├── routers │ │ ├── application.dart │ │ ├── router_handler.dart │ │ └── routers.dart │ └── custom_widgets │ │ ├── myscrollview.dart │ │ ├── progress_dialog.dart │ │ └── custom_titlebar.dart ├── ower │ └── sets │ │ └── update.dart ├── third │ ├── agora │ │ ├── utils │ │ │ ├── settings.dart │ │ │ ├── videosession.dart │ │ │ └── agora_utils.dart │ │ └── pages │ │ │ ├── agorastart.dart │ │ │ ├── index.dart │ │ │ └── index3.dart │ └── jpush │ │ └── JpushModule.dart └── start │ ├── sign_up_page.dart │ ├── titlebardemo.dart │ ├── login.dart │ └── like_button_demo.dart ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── AppDelegate.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── 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-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── main.m │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner.xcodeproj │ ├── project.xcworkspace │ └── contents.xcworkspacedata │ └── xcshareddata │ └── xcschemes │ └── Runner.xcscheme ├── assets └── images │ ├── app_logo.png │ ├── login_logo.png │ ├── ic_take_photo.png │ ├── bg_identify_head.png │ ├── bg_identify_idcard.png │ └── bg_identify_qrcode.png ├── android ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── raw │ │ │ │ │ └── wechat_video.mp3 │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── app_logo.png │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── xml │ │ │ │ │ └── network_security_config.xml │ │ │ │ ├── values │ │ │ │ │ ├── styles.xml │ │ │ │ │ ├── colors.xml │ │ │ │ │ └── dimens.xml │ │ │ │ ├── drawable │ │ │ │ │ ├── shape_little_corner_green_slide.xml │ │ │ │ │ ├── shape_little_corner_blue_slide.xml │ │ │ │ │ └── launch_background.xml │ │ │ │ └── layout │ │ │ │ │ ├── activity_my_webview.xml │ │ │ │ │ └── view_notification_test.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── agora │ │ │ │ │ └── flutter_app1 │ │ │ │ │ ├── my │ │ │ │ │ ├── channel │ │ │ │ │ │ ├── MyChannelUtil.java │ │ │ │ │ │ ├── MyMethodUtil.java │ │ │ │ │ │ ├── DealMethodCall.java │ │ │ │ │ │ └── AndroidToFlutterPlugins.java │ │ │ │ │ └── MyWebviewActivity.java │ │ │ │ │ ├── utils │ │ │ │ │ ├── AppUtils.java │ │ │ │ │ └── MyWebViewUtil.java │ │ │ │ │ └── receiver │ │ │ │ │ └── MyReceiver.java │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── build.gradle ├── .metadata ├── read ├── README.md ├── test └── widget_test.dart ├── .gitignore ├── pubspec.yaml └── pubspec.lock /lib/home/page/database/dbpojo.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /lib/fast/constants/user.dart: -------------------------------------------------------------------------------- 1 | class User{ 2 | var name; 3 | var agoraId; 4 | 5 | 6 | } -------------------------------------------------------------------------------- /assets/images/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/assets/images/app_logo.png -------------------------------------------------------------------------------- /assets/images/login_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/assets/images/login_logo.png -------------------------------------------------------------------------------- /lib/fast/utils/callback.dart: -------------------------------------------------------------------------------- 1 | typedef void PressedOptionCB(String result); 2 | typedef void PressedSureCB(); 3 | 4 | -------------------------------------------------------------------------------- /assets/images/ic_take_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/assets/images/ic_take_photo.png -------------------------------------------------------------------------------- /assets/images/bg_identify_head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/assets/images/bg_identify_head.png -------------------------------------------------------------------------------- /assets/images/bg_identify_idcard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/assets/images/bg_identify_idcard.png -------------------------------------------------------------------------------- /assets/images/bg_identify_qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/assets/images/bg_identify_qrcode.png -------------------------------------------------------------------------------- /android/app/src/main/res/raw/wechat_video.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/android/app/src/main/res/raw/wechat_video.mp3 -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/android/app/src/main/res/mipmap-xxxhdpi/app_logo.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | org.gradle.jvmargs=-Xmx1536M 4 | #android.enableJetifier=true 5 | #android.useAndroidX=true 6 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /lib/ower/sets/update.dart: -------------------------------------------------------------------------------- 1 | class UpdatePojo{ 2 | String versionName ="1.1.7"; 3 | String versionSize = "23.6M"; 4 | String versionIntroduce = "1.添加健康监测模块;\n2.优化预约挂号页面,并修复若干问题;"; 5 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/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/Lightforest/FlutterVideo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightforest/FlutterVideo/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/third/agora/utils/settings.dart: -------------------------------------------------------------------------------- 1 | // Agora AppId 2 | class AgoraConstant{ 3 | static const int QUERY_PEERS_ONLINE_STATUS_ERR_REJECTED = 3 ; 4 | static const String _QUERY_PEERS_ONLINE_STATUS_ERR_REJECTED = "未登录 RTM 系统" ; 5 | 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/fast/utils/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | class AppHelper{ 4 | static const app_name = "flutter学习"; 5 | static const app_logo = ""; 6 | static const app_version_name = "1.0.0"; 7 | static const app_introduce = "这是一款用于记录flutter学习实践的示例信息"; 8 | } -------------------------------------------------------------------------------- /ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/third/agora/utils/videosession.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class VideoSession { 4 | int uid; 5 | Widget view; 6 | int viewId; 7 | 8 | VideoSession(int uid, Widget view) { 9 | this.uid = uid; 10 | this.view = view; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /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-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.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: 8661d8aecd626f7f57ccbcb735553edc05a2e713 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /lib/fast/utils/MethodChannelUtils.dart: -------------------------------------------------------------------------------- 1 | class MethodChannelUtils{ 2 | static const String channelJpush = "com.agora.flutter_app.channe.jpush"; 3 | static const String channelMedia = "com.agora.flutter_app.channe.media"; 4 | 5 | static const String methodStartMedia = "startPlayBell"; 6 | static const String methodStopMedia = "stopPlayBell"; 7 | 8 | } -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /read: -------------------------------------------------------------------------------- 1 | ##const 2 | 在声明变量的时候,除了var,还可以使用const和final,同时,在使用const和final的时候,可以省略var或者其他类型; 3 | const和final定义的都是常量,值不能改变, 4 | const定义的是编译时常量,只能用编译时常量来初始化 5 | final定义的常量可以用变量来初始化 6 | 7 | ##屏幕信息 8 | 导入 import dart:ui ; 9 | 就可以直接这样: 10 | window.devicePixelRatio 获取设备像素比; 11 | window.physicalSize 获取屏幕尺寸; 12 | MediaQuery.of(context).padding.top 状态栏高度 13 | MediaQuery.of(context).size.height 屏幕高度 14 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/agora/flutter_app1/my/channel/MyChannelUtil.java: -------------------------------------------------------------------------------- 1 | package com.agora.flutter_app1.my.channel; 2 | 3 | public class MyChannelUtil { 4 | 5 | //channel的名称,由于app中可能会有多个channel,这个名称需要在app内是唯一的。 6 | public static final String CHANNEL_start_custom_jpush = "com.agora.flutter_app.channe.jpush"; 7 | public static final String CHANNEL_start_play_bell = "com.agora.flutter_app.channe.media"; 8 | } 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/shape_little_corner_green_slide.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/shape_little_corner_blue_slide.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/fast/constants/database.dart: -------------------------------------------------------------------------------- 1 | class MyDataBase{ 2 | static final String DB_NAME1 = "luluflutterapp"; 3 | static final List dbTables = [DB_TABLE_FRIEND]; 4 | static final List dbSql = [friend]; 5 | 6 | static final String DB_TABLE_FRIEND = "friend"; 7 | static final String friend = 'CREATE TABLE friend (id INTEGER PRIMARY KEY, name TEXT, age INTEGER, sex TEXT, birthday TEXT, university TEXT, address TEXT)'; 8 | 9 | } -------------------------------------------------------------------------------- /lib/fast/utils/empty.dart: -------------------------------------------------------------------------------- 1 | class EmptyUtil{ 2 | /// 判断字符串是否为空 3 | static bool textIsEmpty(String text){ 4 | if(text == null){ 5 | return true; 6 | }else if(text.length <= 0){ 7 | return true; 8 | }else{ 9 | return false; 10 | } 11 | } 12 | 13 | static bool listIsEmpty(List list){ 14 | if(list == null){ 15 | return true; 16 | }else if(list.isEmpty){ 17 | return true; 18 | }else{ 19 | return false; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_my_webview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 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 | -------------------------------------------------------------------------------- /lib/fast/routers/application.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluro/fluro.dart'; 3 | 4 | 5 | class Application { 6 | static Router router; 7 | static TabController controller; 8 | //static SpUtil sharePeferences; 9 | 10 | static Map github = { 11 | 'widgetsURL':'https://github.com/alibaba/flutter-go/blob/develop/lib/widgets/', 12 | //'develop':'https://github.com/alibaba-paimai-frontend/flutter-common-widgets-app/tree/develop/lib/widgets/', 13 | //'master':'https://github.com/alibaba-paimai-frontend/flutter-common-widgets-app/tree/master/lib/widgets/' 14 | }; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /lib/home/pojo/menu.dart: -------------------------------------------------------------------------------- 1 | class QuickMenu implements IQuickMenu{ 2 | /// 菜单名称 3 | String name; 4 | /// id 5 | String id; 6 | /// 网络蹄片地址 7 | String image; 8 | /// 页面类型 9 | int windowType; 10 | 11 | 12 | QuickMenu(this.name, this.image); 13 | 14 | @override 15 | String getId() { 16 | return id; 17 | } 18 | 19 | @override 20 | String getName() { 21 | return name; 22 | } 23 | 24 | @override 25 | String getImage() { 26 | return image; 27 | } 28 | 29 | @override 30 | int getWindowType() { 31 | return windowType; 32 | } 33 | 34 | } 35 | abstract class IQuickMenu{ 36 | String getName(); 37 | String getId(); 38 | String getImage(); 39 | int getWindowType(); 40 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/agora/flutter_app1/my/channel/MyMethodUtil.java: -------------------------------------------------------------------------------- 1 | package com.agora.flutter_app1.my.channel; 2 | 3 | public class MyMethodUtil { 4 | public static final String startH5Activity = "pushAndroidWebView"; 5 | 6 | public static final String toFlutterIDCard = "scanIDCard"; 7 | public static final String toFlutterFace = "scanFace"; 8 | public static final String toFlutterQRCode = "scanQRCode"; 9 | 10 | public static final String getFlutterIDCardResult = "registerSendMessage"; 11 | public static final String getFlutterFaceResult = "ScanFaceWebs"; 12 | public static final String startPlayBell = "startPlayBell"; 13 | public static final String stopPlayBell = "stopPlayBell"; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /lib/home/page/camera/camera_pojo.dart: -------------------------------------------------------------------------------- 1 | class IDCardIdentifyResult{ 2 | /*----------------------------------------------身份证-----------------------------------------------*/ 3 | static final String name = "name"; 4 | static final String gender= "gender"; 5 | static final String id_card_number= "id_card_number"; 6 | static final String birthday= "birthday"; 7 | static final String race= "race"; 8 | static final String address= "address"; 9 | static final String side= "side"; 10 | static final String valid_date= "valid_date"; 11 | static final String issued_by= "issued_by"; 12 | /*String name ; 13 | String gender ; 14 | String id_card_number; 15 | String birthday; 16 | String race; 17 | String address; 18 | String side; 19 | String valid_date; 20 | String issued_by;*/ 21 | } -------------------------------------------------------------------------------- /lib/fast/utils/datetime.dart: -------------------------------------------------------------------------------- 1 | class DateTimeUtil{ 2 | /// 获取时间,格式为HH:mm:ss(时分秒) 3 | /// param1- seconds:总秒数 4 | static String getHMmmss_Seconds(int seconds){ 5 | int h = 0,m = 0,s = 0;String result = ""; 6 | if(seconds <= 59){ 7 | return "00:"+getDoubleStr(seconds); 8 | }else{ 9 | m = seconds~/60; 10 | s = seconds % 60; 11 | if(m <= 59){ 12 | return getDoubleStr(m)+":"+getDoubleStr(s); 13 | }else{ 14 | h = m ~/ 60; 15 | m = m % 60; 16 | return getDoubleStr(h)+":"+getDoubleStr(m)+":"+getDoubleStr(s); 17 | } 18 | } 19 | } 20 | static String getDoubleStr(int num){ 21 | try { 22 | if(num < 10){ 23 | return "0"+num.toString(); 24 | }else{ 25 | return num.toString(); 26 | } 27 | } catch (e) { 28 | return "00"; 29 | } 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/agora/flutter_app1/my/channel/DealMethodCall.java: -------------------------------------------------------------------------------- 1 | package com.agora.flutter_app1.my.channel; 2 | 3 | import io.flutter.app.FlutterActivity; 4 | import io.flutter.plugin.common.EventChannel; 5 | 6 | public class DealMethodCall { 7 | 8 | /** 9 | * 通道名称,必须与flutter注册的一致 10 | */ 11 | static final String channels_native_to_flutter = "xinfang/lib/WebViewRoute"; 12 | 13 | /**原生调用flutter方法的回调 14 | * @param activity activity 15 | * @param o o 16 | * @param eventSink eventSink 17 | */ 18 | static void onListen(FlutterActivity activity, Object o, EventChannel.EventSink eventSink){ 19 | //在此调用 20 | eventSink.success("onConnected"); 21 | 22 | } 23 | 24 | /**原生调用flutter方法的回调 25 | * @param activity activity 26 | * @param o o 27 | */ 28 | static void onCancel(FlutterActivity activity, Object o) { 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/fast/utils/permission.dart: -------------------------------------------------------------------------------- 1 | import 'package:permission_handler/permission_handler.dart'; 2 | 3 | class PermissionUtil{ 4 | /// 检查并请求权限 param-权限列表 5 | static Future handlePermission(List permissionList) async { 6 | bool getPerm = false; 7 | for(PermissionGroup p in permissionList){ 8 | /// 检查权限 9 | PermissionStatus permission = await PermissionHandler() 10 | .checkPermissionStatus(p); 11 | if(permission == PermissionStatus.granted){ 12 | getPerm = true; 13 | }else{ 14 | /// 请求权限 15 | Map permissions =await PermissionHandler() 16 | .requestPermissions([p]); 17 | if(permissions[p] == PermissionStatus.granted){ 18 | getPerm = true; 19 | }else{ 20 | getPerm = false; 21 | break; 22 | } 23 | } 24 | } 25 | return getPerm; 26 | } 27 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 声网视频通话在Flutter中的应用 2 | 3 | APP成功运行需要注意以下几个步骤: 4 | 5 | 1.到声网官网注册账号,并申请APPKey。
6 | 2.将申请的APP Key 配置到lib/fast/constants.dart/APPApiKey/Agora_app_id中。
7 | 3.APP跑起来后自定义个userid登录,按以下步骤找到视频部分入口
8 | (若想先跳过登录步骤,可将main.dart文件中的变量_isLogin设为true) 9 | 10 | Agora视频通话示例--自定义视频通话示例--输入好友id后,点击和好友通话即可 11 | 12 | ··“官方视频通话示例”为声网官方对于插件agora_rtc_engine的实现demo
13 | ··“官方信令系统示例”为声网官方对于插件agora_rtm的实现demo
14 | ··“自定义视频通话示例”则是本demo的重点,将以上两个插件结合实现视频的呼叫接听(群视频暂未实现) 15 | 16 | 17 | # 自定义相机 18 | 19 | 自定义相机的实现和webview加载html的功能在一起,按以下步骤运行APP: 20 | 21 | 22 | 1.将main.dart文件中的变量_isLogin设为true
23 | 2.APP跑起来后点击WebView示例,进入百度HTML页面(mywebview.dart),等待三秒即会自动跳入自定义识别身份证的相机页面(调用了方法`startIdentifyIDCard(context)`)。
24 | 3.进入各个自定义相机页面的入口都在mywebview.dart文件中 25 | 26 | lib\home\page\camera\identify_card.dart (自定义识别身份证的相机页面) 27 | lib\home\page\camera\identify_face.dart (自定义识别人脸的相机页面) 28 | lib\home\page\camera\identify_qrcode.dart (自定义扫描二维码的相机页面) 29 | 30 | 31 | 32 | 33 | 34 | # 注意 35 | 36 | *本demo没有完整核验bug,只供部分参考* 37 | 38 | -------------------------------------------------------------------------------- /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:flutter_app1/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 | -------------------------------------------------------------------------------- /lib/fast/constants/constant.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_app1/fast/constants/user.dart'; 2 | 3 | class ConstantKey{ 4 | static final int camera_identify_face = 101; 5 | static final int camera_identify_idcard = 101; 6 | static final int camera_identify_ercode = 101; 7 | 8 | static final String IDCARD_NUM = "id_card_number"; 9 | static final String IDCARD_NAME = "name"; 10 | static final String Web_Identify_IDCard = "Identify_IDCard"; 11 | //static final String Web_Identify_IDCard = "startIdentifyIDCard"; 12 | static final String Web_Identify_Face = "Identify_Face"; 13 | static final String Web_Identify_QRCode = "Identify_QRCode"; 14 | } 15 | 16 | class APPApiKey{ 17 | static final String Face_api_key = "yours"; 18 | static final String Face_api_secret = "yours"; 19 | 20 | static final String Jpush_app_key ="yours"; 21 | static final String Agora_app_id = "yours"; 22 | 23 | } 24 | class SharedKey{ 25 | static final String USER_NAME = "user_name"; 26 | 27 | } 28 | class ConstantObject{ 29 | static User mUser; 30 | static User getUser(){ 31 | if(mUser == null){ 32 | mUser = new User(); 33 | mUser.agoraId = "Rose"; 34 | } 35 | return mUser; 36 | } 37 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/agora/flutter_app1/my/channel/AndroidToFlutterPlugins.java: -------------------------------------------------------------------------------- 1 | package com.agora.flutter_app1.my.channel; 2 | 3 | import io.flutter.app.FlutterActivity; 4 | import io.flutter.plugin.common.EventChannel; 5 | 6 | public class AndroidToFlutterPlugins implements EventChannel.StreamHandler { 7 | 8 | private FlutterActivity activity; 9 | 10 | private AndroidToFlutterPlugins(FlutterActivity activity) { 11 | this.activity = activity; 12 | } 13 | 14 | public static void registerWith(FlutterActivity activity) { 15 | AndroidToFlutterPlugins instance = new AndroidToFlutterPlugins(activity); 16 | //原生调用flutter 17 | EventChannel eventChannel = new EventChannel(activity.registrarFor(DealMethodCall.channels_native_to_flutter) 18 | .messenger(), DealMethodCall.channels_native_to_flutter); 19 | eventChannel.setStreamHandler(instance); 20 | } 21 | 22 | @Override 23 | public void onListen(Object o, EventChannel.EventSink eventSink) { 24 | DealMethodCall.onListen(activity, o, eventSink); 25 | } 26 | 27 | @Override 28 | public void onCancel(Object o) { 29 | DealMethodCall.onCancel(activity, o); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/fast/routers/router_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fluro/fluro.dart'; 3 | 4 | /*import '../widgets/404.dart'; 5 | import 'package:flutter_go/components/full_screen_code_dialog.dart'; 6 | import 'package:flutter_go/views/web_page/web_view_page.dart'; 7 | import 'package:flutter_go/views/first_page/home.dart';*/ 8 | 9 | // app的首页 10 | /*var homeHandler = new Handler( 11 | handlerFunc: (BuildContext context, Map> params) { 12 | return new AppPage(); 13 | }, 14 | ); 15 | 16 | var categoryHandler = new Handler( 17 | handlerFunc: (BuildContext context, Map> params) { 18 | String name = params["type"]?.first; 19 | 20 | return new CategoryHome(name); 21 | }, 22 | ); 23 | 24 | var widgetNotFoundHandler = new Handler( 25 | handlerFunc: (BuildContext context, Map> params) { 26 | return new WidgetNotFound(); 27 | }); 28 | 29 | var fullScreenCodeDialog = new Handler( 30 | handlerFunc: (BuildContext context, Map> params) { 31 | String path = params['filePath']?.first; 32 | return new FullScreenCodeDialog( 33 | filePath: path, 34 | ); 35 | }); 36 | 37 | var webViewPageHand = new Handler( 38 | handlerFunc: (BuildContext context, Map> params) { 39 | String title = params['title']?.first; 40 | String url = params['url']?.first; 41 | return new WebViewPage(url, title); 42 | });*/ 43 | -------------------------------------------------------------------------------- /.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 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.21' 3 | repositories { 4 | google() 5 | jcenter() 6 | /* 7 | maven { url 'https://maven.aliyun.com/repository/google' } 8 | maven { url 'https://maven.aliyun.com/repository/jcenter' } 9 | maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } 10 | * */ 11 | } 12 | 13 | dependencies { 14 | classpath 'com.android.tools.build:gradle:3.2.1' 15 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | google() 22 | jcenter() 23 | } 24 | } 25 | 26 | rootProject.buildDir = '../build' 27 | subprojects { 28 | project.buildDir = "${rootProject.buildDir}/${project.name}" 29 | } 30 | subprojects { 31 | project.evaluationDependsOn(':app') 32 | } 33 | 34 | task clean(type: Delete) { 35 | delete rootProject.buildDir 36 | } 37 | /*subprojects { 38 | project.configurations.all { 39 | resolutionStrategy.eachDependency { details -> 40 | if (details.requested.group == 'com.android.support' && !details.requested.name.contains('multidex') ) { 41 | details.useVersion '1.0.0'//这个版本号设置为你想要的版本 42 | } 43 | if (details.requested.group == 'androidx.lifecycle' && !details.requested.name.contains('multidex') ) { 44 | details.useVersion '2.0.0'//这个版本号设置为你想要的版本 45 | } 46 | *//*if (details.requested.group == 'androidx.core' && !details.requested.name.contains('multidex') ) { 47 | details.useVersion '2.0.0'//这个版本号设置为你想要的版本 48 | }*//* 49 | } 50 | } 51 | }*/ 52 | -------------------------------------------------------------------------------- /lib/fast/custom_widgets/myscrollview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | class ListViewDemo extends BoxScrollView { 4 | // 构造函数 5 | ListViewDemo({ 6 | Key key, 7 | Axis scrollDirection = Axis.vertical, 8 | bool reverse = false, 9 | ScrollController controller, 10 | bool primary, 11 | ScrollPhysics physics, 12 | bool shrinkWrap = false, 13 | EdgeInsetsGeometry padding, 14 | this.itemExtent, 15 | bool addAutomaticKeepAlives = true, 16 | bool addRepaintBoundaries = true, 17 | bool addSemanticIndexes = true, 18 | double cacheExtent, 19 | List children = const [], 20 | int semanticChildCount, 21 | }) : childrenDelegate = SliverChildListDelegate( 22 | children, 23 | addAutomaticKeepAlives: addAutomaticKeepAlives, 24 | addRepaintBoundaries: addRepaintBoundaries, 25 | addSemanticIndexes: addSemanticIndexes, 26 | ), 27 | super( 28 | key: key, 29 | scrollDirection: scrollDirection, 30 | reverse: reverse, 31 | controller: controller, 32 | primary: primary, 33 | physics: physics, 34 | shrinkWrap: shrinkWrap, 35 | padding: padding, 36 | cacheExtent: cacheExtent, 37 | semanticChildCount: semanticChildCount ?? children.length, 38 | ); 39 | 40 | final double itemExtent; 41 | final SliverChildDelegate childrenDelegate; 42 | 43 | // 子类应重写此方法以构建布局模型。 44 | @override 45 | Widget buildChildLayout(BuildContext context) { 46 | if (itemExtent != null) { 47 | return SliverFixedExtentList( 48 | delegate: childrenDelegate, 49 | itemExtent: itemExtent, 50 | ); 51 | } 52 | return SliverList(delegate: childrenDelegate); 53 | } 54 | } -------------------------------------------------------------------------------- /lib/third/agora/utils/agora_utils.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:agora_rtm/agora_rtm.dart'; 3 | import 'package:flutter_app1/fast/constants/constant.dart'; 4 | import 'package:flutter_app1/third/agora/pages/videocall.dart'; 5 | import 'package:flutter_app1/fast/utils/empty.dart'; 6 | 7 | class AgoraUtils{ 8 | 9 | static AgoraRtmClient _client; 10 | static VideoCallState _videoCallState; 11 | 12 | /// Agora 初始化 13 | static Future getAgoraRtmClient() async { 14 | if(_client == null){ 15 | _client = 16 | await AgoraRtmClient.createInstance(APPApiKey.Agora_app_id); 17 | } 18 | return _client; 19 | } 20 | 21 | /// 查询用户是否在线 22 | /// true-在线 , false-离线 23 | static Future queryPeerOnlineStatus(AgoraRtmClient _client, String peerUid) async { 24 | if(EmptyUtil.textIsEmpty(peerUid)){ 25 | return false; 26 | }else{ 27 | try { 28 | Map result = 29 | await _client.queryPeersOnlineStatus([peerUid]); 30 | return result[peerUid]; 31 | } catch (errorCode) { 32 | return false; 33 | } 34 | } 35 | } 36 | /// 获取声网的消息类型 37 | /// 1-请求视频通话 38 | /// 2-取消请求通话 39 | /// 3-拒绝通话请求 40 | static String getAgoraMsgType(int type){ 41 | switch(type){ 42 | case 1: 43 | return "CALLVIDEO"; 44 | case 2: 45 | return "CANCEL_VIDEO"; 46 | case 3: 47 | return "REFUSE_VIDEO"; 48 | default: 49 | return ""; 50 | } 51 | 52 | } 53 | /// 视频请求 54 | static set videoCallState(VideoCallState value) { 55 | _videoCallState = value; 56 | } 57 | /// 视频请求 58 | static VideoCallState get videoCallState => _videoCallState; 59 | 60 | static clearVideoCallState(){ 61 | _videoCallState= null; 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /android/app/src/main/res/layout/view_notification_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 21 | 22 | 28 | 29 | 35 | 36 | 40 | 50 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_app1 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | NSCameraUsageDescription 26 | 测试拍照 27 | NSMicrophoneUsageDescription 28 | 测试麦克风 29 | NSPhotoLibraryAddUsageDescription 30 | 测试选择图片 31 | NSPhotoLibraryUsageDescription 32 | 33 | UILaunchStoryboardName 34 | LaunchScreen 35 | UIMainStoryboardFile 36 | Main 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | NSAppTransportSecurity 53 | 54 | NSAllowsArbitraryLoads 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /lib/fast/custom_widgets/progress_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'package:flutter/material.dart';//导入系统基础包 4 | 5 | 6 | class ShowProgress extends StatefulWidget { 7 | ShowProgress(this.requestCallback); 8 | final Future requestCallback;//这里Null表示回调的时候不指定类型 9 | @override 10 | _ShowProgressState createState() => new _ShowProgressState(); 11 | } 12 | 13 | class _ShowProgressState extends State { 14 | @override 15 | initState() { 16 | super.initState(); 17 | new Timer(new Duration(milliseconds: 10), () {//每隔10ms回调一次 18 | widget.requestCallback.then((Null) {//这里Null表示回调的时候不指定类型 19 | Navigator.of(context).pop();//所以pop()里面不需要传参,这里关闭对话框并获取回调的值 20 | }); 21 | }); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return new Center( 27 | child: new CircularProgressIndicator(), 28 | ); 29 | } 30 | } 31 | ////////////上面是对话框控件,下面是按钮控件///////////////// 32 | class ClickEvent extends StatefulWidget{ 33 | @override 34 | _ClickEventState createState() { 35 | return new _ClickEventState(); 36 | } 37 | } 38 | 39 | getProgressDialog(){ 40 | runApp(ClickEvent()); 41 | } 42 | class _ClickEventState extends State{ 43 | Future _myClick() { 44 | return showDialog( 45 | context: context, 46 | barrierDismissible: true, // false表示必须点击按钮才能关闭 47 | child:new ShowProgress(_postData())//将网络请求的方法_postData作为参数传递给ShowProgress显示对话框 48 | ); 49 | } 50 | var httpclient=new HttpClient();//获取http对象 51 | var url='https://api.github.com/'; 52 | var response; 53 | //核心的网络请求方法 54 | _postData() async{ 55 | var request = await httpclient.getUrl(Uri.parse(url)); 56 | response = await request.close(); 57 | //response=await httpclient.req(url);//发送网络请求,read()表示读取返回的结果,get()表示不读取返回的结果 58 | print('Response=$response'); 59 | /* Map data= JSON.decode(response); 60 | var url1= data['current_user_url']; 61 | print('current_user_url:$url1');*/ 62 | } 63 | @override 64 | Widget build(BuildContext context) { 65 | return new Scaffold( 66 | appBar: new AppBar( 67 | title: new Text('网络请求'), 68 | ), 69 | floatingActionButton: new FloatingActionButton( 70 | child: new Text('获取数据'), 71 | onPressed: _myClick), 72 | ); 73 | } 74 | } -------------------------------------------------------------------------------- /lib/home/page/database/friend.dart: -------------------------------------------------------------------------------- 1 | /// @Author: 一凨 2 | /// @Date: 2019-01-07 16:24:42 3 | /// @Last Modified by: 一凨 4 | /// @Last Modified time: 2019-01-08 17:37:42 5 | 6 | import 'dart:async'; 7 | 8 | import 'package:flutter_app1/fast/constants/database.dart'; 9 | import 'package:flutter_app1/fast/utils/sql.dart'; 10 | 11 | 12 | abstract class FriendInterface { 13 | String get name; 14 | String get sex; 15 | int get age; 16 | String get birthday; 17 | String get university; 18 | String get address; 19 | 20 | } 21 | 22 | class Friend implements FriendInterface { 23 | String name; 24 | String sex; 25 | int age; 26 | String birthday; 27 | String university; 28 | String address; 29 | 30 | Friend({this.name,this.sex,this.age,this.birthday,this.university,this.address}); 31 | 32 | factory Friend.fromJSON(Map json){ 33 | return Friend( 34 | name: json['name'], 35 | sex: json['sex'], 36 | age: json['age'], 37 | birthday: json['birthday'], 38 | university: json['university'], 39 | address: json['address'], 40 | 41 | ); 42 | } 43 | 44 | Object toMap() { 45 | return {'name': name, 'sex': sex, 'age': age, 'birthday': birthday, 'university': university, 'address': address}; 46 | } 47 | } 48 | 49 | class FriendControlModel { 50 | final String table = MyDataBase.DB_TABLE_FRIEND; 51 | Sql sql; 52 | 53 | FriendControlModel() { 54 | sql = Sql.setTable(table); 55 | } 56 | 57 | // 获取所有的收藏 58 | 59 | // 插入新收藏 60 | Future insert(Friend friend) { 61 | var result = 62 | sql.insert({'name': friend.name, 'sex': friend.sex, 'age': friend.age, 63 | 'birthday': friend.birthday, 'university': friend.university, 'address': friend.address}); 64 | return result; 65 | } 66 | 67 | // 获取全部的收藏 68 | Future> getAllFriend() async { 69 | List list = await sql.getByCondition(); 70 | List resultList = []; 71 | list.forEach((item){ 72 | print(item); 73 | resultList.add(Friend.fromJSON(item)); 74 | }); 75 | return resultList; 76 | } 77 | 78 | // 通过收藏名获取router 79 | Future getRouterByName(String name) async { 80 | List list = await sql.getByCondition(conditions: {'name': name}); 81 | return list; 82 | } 83 | 84 | // 删除 85 | Future deleteByName(String name) async{ 86 | return await sql.delete(name,'name'); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 11 | 19 | 20 | 25 | 32 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_app1 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 | english_words: ^3.1.0 27 | flutter_webview_plugin: ^0.3.0+2 28 | path_provider: ^0.5.0 29 | video_player: 0.10.0+4 30 | fluttertoast: ^2.1.1 31 | camera: 0.4.2 32 | orientation: 1.0.4 33 | dio: ^2.1.0 34 | fluro: ^1.3.4 35 | flutter_image_compress: 0.3.1 36 | flutter_spinkit: ^3.0.0 37 | webview_flutter: ^0.3.7+1 38 | jpush_flutter: 0.0.11 39 | agora_rtc_engine: 0.9.4 40 | permission_handler: ^3.1.0 41 | agora_rtm: 0.9.3 42 | shared_preferences: 0.5.3 43 | sqflite: ^1.1.6 44 | flutter_screenutil: 0.5.3 45 | random_pk: 0.0.3 46 | font_awesome_flutter: 8.5.0 47 | like_button: 0.1.7 48 | animatedloginbutton: ^0.1.1 49 | 50 | dev_dependencies: 51 | flutter_test: 52 | sdk: flutter 53 | 54 | 55 | # For information on the generic Dart part of this file, see the 56 | # following page: https://www.dartlang.org/tools/pub/pubspec 57 | 58 | # The following section is specific to Flutter. 59 | flutter: 60 | #plugin: 61 | # androidPackage: com.agora.flutter_app 62 | # pluginClass: AgoraRtmPlugin 63 | 64 | # The following line ensures that the Material Icons font is 65 | # included with your application, so that you can use the icons in 66 | # the material Icons class. 67 | uses-material-design: true 68 | 69 | assets: 70 | - assets/images/bg_identify_head.png 71 | - assets/images/bg_identify_idcard.png 72 | - assets/images/bg_identify_qrcode.png 73 | - assets/images/ic_take_photo.png 74 | - assets/images/login_logo.png 75 | - assets/images/app_logo.png 76 | 77 | -------------------------------------------------------------------------------- /lib/fast/utils/sql.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:sqflite/sqflite.dart'; 4 | 5 | import './provider.dart'; 6 | 7 | class BaseModel{ 8 | Database db; 9 | final String table = ''; 10 | var query; 11 | BaseModel(this.db){ 12 | query = db.query; 13 | } 14 | } 15 | 16 | class Sql extends BaseModel { 17 | final String tableName; 18 | Sql.setTable(String name) 19 | : tableName = name, 20 | super(Provider.db); 21 | 22 | // sdf 23 | Future get() async{ 24 | return await this.query(tableName); 25 | } 26 | String getTableName () { 27 | return tableName; 28 | } 29 | 30 | Future delete(String value,String key) async{ 31 | return await this.db.delete(tableName,where:'$key = ?',whereArgs:[value]); 32 | } 33 | 34 | Future getByCondition({Map conditions}) async { 35 | if (conditions == null || conditions.isEmpty) { 36 | return this.get(); 37 | } 38 | String stringConditions = ''; 39 | 40 | int index = 0; 41 | conditions.forEach((key, value) { 42 | if (value == null) { 43 | return ; 44 | } 45 | if (value.runtimeType == String) { 46 | stringConditions = '$stringConditions $key = "$value"'; 47 | } 48 | if (value.runtimeType == int) { 49 | stringConditions = '$stringConditions $key = $value'; 50 | } 51 | 52 | if (index >= 0 && index < conditions.length -1) { 53 | stringConditions = '$stringConditions and'; 54 | } 55 | index++; 56 | }); 57 | // print("this is string condition for sql > $stringConditions"); 58 | return await this.query(tableName, where: stringConditions); 59 | } 60 | Future> insert(Map json) async { 61 | var id = await this.db.insert(tableName, json); 62 | json['id'] = id; 63 | return json; 64 | } 65 | /// 66 | /// 搜索 67 | /// @param Object condition 68 | /// @mods [And, Or] default is Or 69 | /// search({'name': "hanxu', 'id': 1}; 70 | /// 71 | Future search({Map conditions, String mods = 'Or'}) async { 72 | if (conditions == null || conditions.isEmpty) { 73 | return this.get(); 74 | } 75 | String stringConditions = ''; 76 | int index = 0; 77 | conditions.forEach((key, value) { 78 | if (value == null) { 79 | return ; 80 | } 81 | 82 | if (value.runtimeType == String) { 83 | stringConditions = '$stringConditions $key like "%$value%"'; 84 | } 85 | if (value.runtimeType == int) { 86 | stringConditions = '$stringConditions $key = "%$value%"'; 87 | } 88 | 89 | if (index >= 0 && index < conditions.length -1) { 90 | stringConditions = '$stringConditions $mods'; 91 | } 92 | index++; 93 | }); 94 | 95 | return await this.query(tableName, where: stringConditions); 96 | } 97 | } -------------------------------------------------------------------------------- /lib/fast/utils/value.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class ThemeColors { 6 | ///主色调,按钮,特殊需要强调和突出的文字 7 | //static Color colorTheme = Color.fromARGB(255, 193, 219, 146); 8 | static Color colorTheme = Colors.green; 9 | ///主色调渐变用色,个别按钮和状态,从colorBtnLeft变化到colorBtnRight 10 | static Color colorBtnLeft = Color.fromARGB(255, 251, 156, 51); 11 | static Color colorBtnRight = Color.fromARGB(255, 252, 191, 50); 12 | ///提示性文字,状态信息,按钮等 13 | static Color colorRed = Color.fromARGB(255, 226, 36, 39); 14 | ///功能性较强的文字,内页标题等 15 | static Color color333333 = Color.fromARGB(255, 51, 51, 51); 16 | ///正文,副标题以及可点击区域的主要文字和图标 17 | static Color color666666 = Color.fromARGB(255, 102, 102, 102); 18 | ///弱化信息,提示性文字信息,不可点击状态 19 | static Color color999999 = Color.fromARGB(255, 153, 153, 153); 20 | static Color colorAAA = Color.fromARGB(255, 170, 170, 170); 21 | ///弱化信息,提示性文字信息 22 | static Color colorDDDDDD = Color.fromARGB(255, 221, 221, 221); 23 | static Color colorEEEEEE = Color.fromARGB(255, 238, 238, 238); 24 | static Color colorF1F1F1 = Color.fromARGB(255, 241,241,241); 25 | ///背景区域划分,分割线 26 | static Color colorF6F6F8 = Color.fromARGB(255, 246, 246, 248); 27 | ///纯白色 28 | static Color colorWhite = Color.fromARGB(255, 255, 255, 255); 29 | ///纯黑色 30 | static Color colorBlack = Color.fromARGB(255, 0, 0, 0); 31 | /// 主图背景色 32 | static Color colorSmokeWhite = Color.fromARGB(255, 245, 245, 245); 33 | static Color colorF9F9F9 = Color.fromARGB(255, 249, 249, 249); 34 | 35 | static Color transparent = Colors.transparent; 36 | static Color transparent1 = Color.fromARGB(150, 0, 0, 0); 37 | 38 | 39 | } 40 | class TextSize{ 41 | /// 12 42 | static double font_m = 12.0; 43 | /// 28 44 | static double font_h = 28.0; 45 | /// 30 46 | static double font_xh = 30.0; 47 | /// 32 48 | static double font_xxh = 32.0; 49 | /// 36 50 | static double font_xxxh = 36.0; 51 | /// 42 52 | static double font_xxxxh = 42.0; 53 | 54 | 55 | static double bottom = 12.0; 56 | static double caption = 10.0; 57 | static double body1 = 16.0; 58 | static double body2 = 17.0; 59 | static double subheading = 18.0; 60 | static double title = 20.0; 61 | static double headline = 24.0; 62 | static double display1 = 26.0; 63 | static double display2 = 30.0; 64 | static double display3 = 36.0; 65 | static double display4 = 40.0; 66 | 67 | static double basicFont = 10.0; 68 | static double add1 = 11.0; 69 | static double add2 = 12.0; 70 | static double add4 = 14.0; 71 | static double add6 = 16.0; 72 | static double add8 = 18.0; 73 | static double add10 = 20.0; 74 | static double add12 = 22.0; 75 | static double add14 = 24.0; 76 | static double add16 = 26.0; 77 | static double add18 = 28.0; 78 | static double add20 = 30.0; 79 | static double add26 = 36.0; 80 | static double add30 = 40.0; 81 | static double add40 = 50.0; 82 | } 83 | -------------------------------------------------------------------------------- /lib/fast/utils/shared_preferences.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:async'; 3 | 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | 6 | 7 | /// 用来做shared_preferences的存储 8 | class SpUtil { 9 | static SpUtil _instance; 10 | static Future get instance async { 11 | return await getInstance(); 12 | } 13 | 14 | static SharedPreferences _spf; 15 | 16 | 17 | SpUtil._(); 18 | 19 | Future _init() async { 20 | _spf = await SharedPreferences.getInstance(); 21 | } 22 | 23 | static Future getInstance() async { 24 | if (_instance == null) { 25 | _instance = new SpUtil._(); 26 | await _instance._init(); 27 | 28 | } 29 | return _instance; 30 | } 31 | 32 | static bool _beforeCheck() { 33 | if (_spf == null) { 34 | return true; 35 | } 36 | return false; 37 | } 38 | // 判断是否存在数据 39 | bool hasKey(String key) { 40 | Set keys = getKeys(); 41 | return keys.contains(key); 42 | } 43 | 44 | Set getKeys() { 45 | if (_beforeCheck()) return null; 46 | return _spf.getKeys(); 47 | } 48 | 49 | get(String key) { 50 | if (_beforeCheck()) return null; 51 | return _spf.get(key); 52 | } 53 | 54 | getString(String key) { 55 | if (_beforeCheck()) return null; 56 | return _spf.getString(key); 57 | } 58 | 59 | Future putString(String key, String value) { 60 | if (_beforeCheck()) return null; 61 | return _spf.setString(key, value); 62 | } 63 | 64 | bool getBool(String key) { 65 | if (_beforeCheck()) return null; 66 | return _spf.getBool(key); 67 | } 68 | 69 | Future putBool(String key, bool value) { 70 | if (_beforeCheck()) return null; 71 | return _spf.setBool(key, value); 72 | } 73 | 74 | int getInt(String key) { 75 | if (_beforeCheck()) return null; 76 | return _spf.getInt(key); 77 | } 78 | 79 | Future putInt(String key, int value) { 80 | if (_beforeCheck()) return null; 81 | return _spf.setInt(key, value); 82 | } 83 | 84 | double getDouble(String key) { 85 | if (_beforeCheck()) return null; 86 | return _spf.getDouble(key); 87 | } 88 | 89 | Future putDouble(String key, double value) { 90 | if (_beforeCheck()) return null; 91 | return _spf.setDouble(key, value); 92 | } 93 | 94 | List getStringList(String key) { 95 | return _spf.getStringList(key); 96 | } 97 | 98 | Future putStringList(String key, List value) { 99 | if (_beforeCheck()) return null; 100 | return _spf.setStringList(key, value); 101 | } 102 | 103 | dynamic getDynamic(String key) { 104 | if (_beforeCheck()) return null; 105 | return _spf.get(key); 106 | } 107 | 108 | 109 | 110 | Future remove(String key) { 111 | if (_beforeCheck()) return null; 112 | return _spf.remove(key); 113 | } 114 | 115 | Future clear() { 116 | if (_beforeCheck()) return null; 117 | return _spf.clear(); 118 | } 119 | } -------------------------------------------------------------------------------- /lib/third/agora/pages/agorastart.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_app1/third/agora/pages/index.dart'; 4 | import 'package:flutter_app1/third/agora/pages/index2.dart'; 5 | import 'package:flutter_app1/third/agora/pages/index3.dart'; 6 | import 'package:flutter_app1/fast/utils/value.dart'; 7 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 8 | 9 | class AgoraStartPage extends StatefulWidget { 10 | @override 11 | createState() => new AgoraStartState(); 12 | } 13 | 14 | class AgoraStartState extends State { 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return new Scaffold( 19 | appBar: new AppBar( 20 | title: new Text("声网"), 21 | ), 22 | body: buildStartPage(), 23 | ); 24 | } 25 | Widget buildStartPage(){ 26 | return Column(children: [ 27 | Container( 28 | width: double.infinity, 29 | height: 50, 30 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 31 | child: RaisedButton( 32 | onPressed: (){ 33 | try{ 34 | Navigator.push(context, new MaterialPageRoute( 35 | builder: (BuildContext context) { 36 | return new IndexPage(); 37 | })); 38 | }catch(e){ 39 | print(e.toString()); 40 | } 41 | }, 42 | // 文本内容 43 | child: Text("官方视频通话示例"), 44 | // 按钮颜色 45 | color: ThemeColors.colorTheme, 46 | )), 47 | Container( 48 | width: double.infinity, 49 | height: 50, 50 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 51 | child: RaisedButton( 52 | onPressed: (){ 53 | try{ 54 | Navigator.push(context, new MaterialPageRoute( 55 | builder: (BuildContext context) { 56 | return new AgoraRTMPage(); 57 | })); 58 | }catch(e){ 59 | print(e.toString()); 60 | } 61 | }, 62 | // 文本内容 63 | child: Text("官方信令系统示例"), 64 | // 按钮颜色 65 | color: ThemeColors.colorTheme, 66 | )), 67 | Container( 68 | width: double.infinity, 69 | height: 50, 70 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 71 | child: RaisedButton( 72 | onPressed: (){ 73 | try{ 74 | Navigator.push(context, new MaterialPageRoute( 75 | builder: (BuildContext context) { 76 | return new AgoraCustomPage(); 77 | })); 78 | }catch(e){ 79 | print(e.toString()); 80 | } 81 | }, 82 | // 文本内容 83 | child: Text("自定义视频通话示例(运用以上两个插件)"), 84 | // 按钮颜色 85 | color: ThemeColors.colorTheme, 86 | )), 87 | ]); 88 | } 89 | } -------------------------------------------------------------------------------- /lib/fast/routers/routers.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:convert'; 3 | 4 | import 'package:fluro/fluro.dart'; 5 | import 'package:flutter/cupertino.dart'; 6 | import 'package:flutter_app1/home/page/webview/mywebview.dart'; 7 | import 'package:flutter_app1/third/agora/pages/agorastart.dart'; 8 | import 'package:flutter_app1/third/agora/pages/videoanswer.dart'; 9 | import 'package:flutter_app1/third/agora/pages/videocall.dart'; 10 | import 'package:flutter_app1/third/jpush/jpushpage.dart'; 11 | 12 | class Routes { 13 | /** 这里需要注意的事首页一定要用“/”配置,其它页无所谓。 */ 14 | static Router router; 15 | static String root = "/"; 16 | static String home = "/home"; 17 | static String call = '/third/agora/pages/videocall'; 18 | static String answer = '/third/agora/pages/videoanswer'; 19 | static String webview = "/home/page/webview"; 20 | static String jiguang = "/third/jpush/jpushpage"; 21 | static String agora = "/third/agora/pages/agorastart"; 22 | 23 | 24 | /* static void configureRoutes(Router router) { 25 | List widgetDemosList = new WidgetDemoList().getDemos(); 26 | router.notFoundHandler = new Handler( 27 | handlerFunc: (BuildContext context, Map> params) { 28 | }); 29 | router.define(home, handler: homeHandler); 30 | 31 | router.define('/category/:type', handler: categoryHandler); 32 | router.define('/category/error/404', handler: widgetNotFoundHandler); 33 | router.define(codeView,handler:fullScreenCodeDialog); 34 | router.define(webViewPage,handler:webViewPageHand); 35 | widgetDemosList.forEach((demo) { 36 | Handler handler = new Handler( 37 | handlerFunc: (BuildContext context, Map> params) { 38 | return demo.buildRouter(context); 39 | }); 40 | router.define('${demo.routerName}', handler: handler); 41 | }); 42 | }*/ 43 | static void configureRoutes(Router router) { 44 | router.define( 45 | webview, handler: Handler(handlerFunc: (context, params) => MyWebview())); 46 | router.define( 47 | jiguang, handler: Handler(handlerFunc: (context, params) => JPushPage())); 48 | router.define( 49 | webview, handler: Handler(handlerFunc: (context, params) => AgoraStartPage())); 50 | /*router.define( 51 | //相当于跳转的链接 52 | answer, 53 | //用来获取传参和创建界面 54 | handler: Handler(handlerFunc: (context, params) { 55 | var message = params['message']?.first;//取出传参 56 | return VideoAnswerPage(message); 57 | }));*/ 58 | Routes.router = router; 59 | } 60 | static void toAppointedPage(Router router,String rootPath,Widget widget) { 61 | if(router != null){ 62 | router.define( 63 | rootPath, handler: Handler(handlerFunc: (context, params) => widget)); 64 | } 65 | /*var json = jsonEncode(Utf8Encoder().convert('来自第一个界面')); 66 | router.navigateTo( context, '${Routes.page2}?message=$json', 67 | //跳转路径 68 | transition: TransitionType.inFromRight//过场效果 69 | ).then((result) { 70 | //回传值 71 | if (result != null) { 72 | //message = result; 73 | } });*/ 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /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 from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.agora.flutter_app1" 37 | minSdkVersion 21 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 42 | 43 | ndk { 44 | //选择要添加的对应cpu类型的.so库。 45 | abiFilters 'armeabi', 'armeabi-v7a', 'x86', 'x86_64', 'mips', 'mips64', 'arm64-v8a' 46 | // 还可以添加 'armeabi', 'armeabi-v7a', 'x86', 'x86_64', 'mips', 'mips64', 'arm64-v8a', 47 | } 48 | manifestPlaceholders = [ 49 | JPUSH_PKGNAME : applicationId, 50 | JPUSH_APPKEY : "yours", // NOTE: JPush 上注册的包名对应的 Appkey. 51 | JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可. 52 | ] 53 | } 54 | buildTypes { 55 | release { 56 | // TODO: Add your own signing config for the release build. 57 | // Signing with the debug keys for now, so `flutter run --release` works. 58 | signingConfig signingConfigs.debug 59 | } 60 | } 61 | /*dataBinding { 62 | enabled = true 63 | }*/ 64 | packagingOptions { 65 | exclude 'lib/arm64-v8a/libgojni.so' 66 | exclude 'lib/x86/libgojni.so' 67 | exclude 'lib/x86_64/libgojni.so' 68 | } 69 | } 70 | 71 | flutter { 72 | source '../..' 73 | } 74 | 75 | dependencies { 76 | testImplementation 'junit:junit:4.12' 77 | androidTestImplementation 'androidx.test:runner:1.1.2-alpha02' 78 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 79 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 80 | //compile project(path:'cn.jiguang.sdk:jpush-3.1.6') 81 | implementation 'cn.jiguang.sdk:jpush:3.1.6' 82 | implementation 'cn.jiguang.sdk:jcore:1.2.5' 83 | // implementation 'io.third.agora.rtm:rtm-sdk:0.9.2' 84 | } 85 | -------------------------------------------------------------------------------- /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.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /lib/fast/utils/provider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:flutter_app1/fast/constants/database.dart'; 6 | import 'package:path/path.dart'; 7 | import 'package:sqflite/sqflite.dart'; 8 | import 'package:flutter/services.dart' show rootBundle; 9 | 10 | /*const createSql = { 11 | 'cat': """ 12 | CREATE TABLE "cat" ( 13 | `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, 14 | `name` TEXT NOT NULL UNIQUE, 15 | `depth` INTEGER NOT NULL DEFAULT 1, 16 | `parentId` INTEGER NOT NULL, 17 | `desc` TEXT 18 | ); 19 | """, 20 | 'collectio': """ 21 | CREATE TABLE collection (id INTEGER PRIMARY KEY NOT NULL UNIQUE, name TEXT NOT NULL, router TEXT); 22 | """, 23 | 'widget': """ 24 | CREATE TABLE widget (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, name TEXT NOT NULL, cnName TEXT NOT NULL, image TEXT NOT NULL, doc TEXT, demo TEXT, catId INTEGER NOT NULL REFERENCES cat (id), owner TEXT); 25 | """; 26 | };*/ 27 | 28 | 29 | class Provider { 30 | static Database db; 31 | 32 | // 获取数据库中所有的表 33 | Future getTables() async { 34 | if (db == null) { 35 | return Future.value([]); 36 | } 37 | List tables = await db.rawQuery('SELECT name FROM sqlite_master WHERE type = "table"'); 38 | List targetList = []; 39 | tables.forEach((item) { 40 | targetList.add(item['name']); 41 | }); 42 | return targetList; 43 | } 44 | 45 | // 检查数据库中, 表是否完整, 在部份android中, 会出现表丢失的情况 46 | Future checkTableIsRight() async { 47 | List expectTables = MyDataBase.dbTables; 48 | 49 | List tables = await getTables(); 50 | 51 | for(int i = 0; i < expectTables.length; i++) { 52 | if (!tables.contains(expectTables[i])) { 53 | return false; 54 | } 55 | } 56 | return true; 57 | } 58 | Future checkTableAndCreate() async { 59 | List expectTables = MyDataBase.dbTables; 60 | List tables = await getTables(); 61 | 62 | for(int i = 0; i < expectTables.length; i++) { 63 | if (!tables.contains(expectTables[i])) { 64 | createTable(MyDataBase.dbSql[i]); 65 | } 66 | } 67 | } 68 | Future createTable(String sqlName) async { 69 | if(db != null ) { 70 | await db.execute(sqlName); 71 | } 72 | } 73 | 74 | //初始化数据库 75 | Future init(bool isCreate) async { 76 | // 获取数据库路径 77 | String databasesPath = await getDatabasesPath();//获取数据库路径 sqflite三方 78 | String path = join(databasesPath,MyDataBase.DB_NAME1 );//拼接App数据库名称 79 | print(path); 80 | 81 | // 创建数据库(表) 82 | try { 83 | db = await openDatabase(path );//尝试打开数据库 如果已经创建 84 | } catch (e) { 85 | print("Error $e"); 86 | } 87 | checkTableAndCreate(); 88 | //bool tableIsRight = await this.checkTableIsRight();//检查数据库中表是否完整 89 | 90 | /*if (!tableIsRight) {//如果不完整就删除重新创建 91 | // 关闭上面打开的db,否则无法执行open 92 | db.close(); 93 | // Delete the database 94 | await deleteDatabase(path); 95 | ByteData data = await rootBundle.load(join("assets", "app.db"));//项目本地文件 96 | List bytes = 97 | data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); 98 | await new File(path).writeAsBytes(bytes); 99 | 100 | db = await openDatabase(path, version: 1, 101 | onCreate: (Database db, int version) async { 102 | print('db created version is $version'); 103 | }, onOpen: (Database db) async { 104 | print('new db opened'); 105 | }); 106 | } else { 107 | print("Opening existing database"); 108 | }*/ 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lib/third/jpush/JpushModule.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_app1/fast/constants/constant.dart'; 2 | import 'package:jpush_flutter/jpush_flutter.dart'; 3 | 4 | class JpushNotification{ 5 | 6 | 7 | JPush jpush; 8 | void initJpush (){ 9 | createJpush (); 10 | addJpushEventHandler(); 11 | setupJpush(); 12 | } 13 | JPush createJpush (){ 14 | jpush = new JPush(); 15 | return jpush; 16 | } 17 | void addJpushEventHandler(){ 18 | if(jpush == null){ 19 | createJpush (); 20 | } 21 | jpush.addEventHandler( 22 | // 接收通知回调方法。 23 | onReceiveNotification: (Map message) async { 24 | // 可以收到附加消息字段 25 | print("flutter onReceiveNotification: $message"); 26 | }, 27 | // 点击通知回调方法。 28 | onOpenNotification: (Map message) async { 29 | print("flutter onOpenNotification: $message"); 30 | }, 31 | // 接收自定义消息回调方法。 32 | onReceiveMessage: (Map message) async { 33 | print("flutter onReceiveMessage: $message"); 34 | }, 35 | ); 36 | } 37 | /// 初始化 JPush SDK 、 将缓存的事件下发到 dart 环境中 38 | void setupJpush(){ 39 | if(jpush == null){ 40 | createJpush(); 41 | } 42 | jpush.setup( 43 | appKey: APPApiKey.Jpush_app_key, 44 | channel: "theChannel", 45 | production: false, 46 | debug: true, // 设置是否打印 debug 日志 47 | ); 48 | } 49 | /// 获取 registrationId,这个 JPush 运行通过 registrationId 来进行推送 50 | String getJpushRegistrationID(){ 51 | if(jpush == null){ 52 | createJpush(); 53 | } 54 | jpush.getRegistrationID().then((rid ) { 55 | print(rid); 56 | }); 57 | } 58 | /// 停止推送功能,调用该方法将不会接收到通知 59 | void stopPush(){ 60 | if(jpush == null){ 61 | createJpush(); 62 | } 63 | jpush.stopPush(); 64 | } 65 | /// 调用 stopPush 后,可以通过 resumePush 方法恢复推送 66 | void resumePush(){ 67 | if(jpush == null){ 68 | createJpush(); 69 | } 70 | jpush.resumePush(); 71 | } 72 | /// 设置别名,极光后台可以通过别名来推送,一个 App 应用只有一个别名,一般用来存储用户 id 73 | void setJpushAlias(String alias){ 74 | if(jpush == null){ 75 | createJpush(); 76 | } 77 | if(alias != null && alias != ""){ 78 | jpush.setAlias(alias).then((map) { }); 79 | } 80 | } 81 | /// 可以通过 deleteAlias 方法来删除已经设置的 alias 82 | void deleteJpushAlias(){ 83 | if(jpush == null){ 84 | createJpush(); 85 | } 86 | jpush.deleteAlias().then((map) {}); 87 | } 88 | /// ios only 89 | void applyPushAuthority(){ 90 | if(jpush == null){ 91 | createJpush(); 92 | } 93 | jpush.applyPushAuthority(new NotificationSettingsIOS( 94 | sound: true, 95 | alert: true, 96 | badge: true)); 97 | } 98 | /// 重置 tags。 99 | void setJpushTags(List tags){ 100 | if(jpush == null){ 101 | createJpush(); 102 | } 103 | if(tags != null ){ 104 | jpush.setTags(tags).then((map) { }); 105 | } 106 | } 107 | /// 在原来的 Tags 列表上删除指定 tags。 108 | void addJpushTags(List tags){ 109 | if(jpush == null){ 110 | createJpush(); 111 | } 112 | if(tags != null ){ 113 | jpush.addTags(tags).then((map) { }); 114 | } 115 | } 116 | /// 可以通过 deleteTags 方法来删除已经设置的 tags 117 | void deleteJpushTags(List tags){ 118 | if(jpush == null){ 119 | createJpush(); 120 | } 121 | jpush.deleteTags(tags).then((map) {}); 122 | } 123 | Map getJpushAllTags(){ 124 | Map tags; 125 | jpush.getAllTags().then((map) { 126 | tags = map; 127 | return tags; 128 | }); 129 | } 130 | void cleanJpushTags(){ 131 | if(jpush == null){ 132 | createJpush(); 133 | } 134 | jpush.cleanTags( ).then((map) {}); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #FFFFFF 5 | #FFA500 6 | #FF0000 7 | #F5F5F5 8 | #DCDCDC 9 | #A9A9A9 10 | #808080 11 | #4682B4 12 | #00BFFF 13 | #008000 14 | #000000 15 | #5E5E5E 16 | #0000 17 | #0fff 18 | #cfff 19 | #6000 20 | 21 | #54B7CA 22 | #303F9F 23 | #54B7CA 24 | #f5f5f5 25 | #eeeeee 26 | #f69429 27 | #ababab 28 | 29 | 30 | 31 | 32 | #AAAAAA 33 | 34 | 35 | 36 | #FF6C00 37 | #C1644B 38 | 39 | #F9F9F9 40 | 41 | 42 | #54B7CA 43 | 44 | #F1F1F1 45 | #F8F8F8 46 | #FFFFFF 47 | #F5F5F5 48 | #FDFDFD 49 | #e5e5e5 50 | #66F5F5F5 51 | #2DA3F8 52 | #09B6F2 53 | #2e3233 54 | #333333 55 | #555555 56 | #585858 57 | #666666 58 | #999999 59 | #aaaaaa 60 | #eeeeee 61 | #E6E6E4 62 | #f7f7f7 63 | #f69429 64 | #86a149 65 | #77D4DC 66 | #07AD94 67 | #fbeae0 68 | #119EA7 69 | #C8EEF1 70 | #139bb4 71 | #00A5CA 72 | #888888 73 | #C95371 74 | #6DC3D3 75 | #139BB3 76 | #c95472 77 | #f58642 78 | #ccc 79 | #e4f5f8 80 | #f0fcfe 81 | #E1FAFF 82 | #9DD9E6 83 | #90CF00 84 | #F3F3F3 85 | #27A4BA 86 | 87 | 88 | -------------------------------------------------------------------------------- /lib/home/page/dialog/dialogdemo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_app1/fast/utils/dialog.dart'; 4 | import 'package:flutter_app1/fast/utils/empty.dart'; 5 | import 'package:flutter_app1/fast/utils/value.dart'; 6 | import 'package:flutter_app1/ower/sets/update.dart'; 7 | 8 | class MyDialogPage extends StatefulWidget { 9 | 10 | @override 11 | createState() => new MyDialogState(); 12 | } 13 | 14 | class MyDialogState extends State { 15 | List strList = new List(); 16 | String alert = ""; 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar( 21 | title: Text('Dialog'), 22 | ), 23 | backgroundColor: ThemeColors.colorSmokeWhite, 24 | body:Column(children: [ 25 | Container( 26 | width: double.infinity,height: 50, 27 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 28 | child: RaisedButton( 29 | onPressed: (){ 30 | _showToastDialog(); 31 | }, 32 | // 文本内容 33 | child: Text("showToastDialog"), 34 | // 按钮颜色 35 | color: ThemeColors.colorTheme, 36 | )), 37 | Container( 38 | width: double.infinity,height: 50, 39 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 40 | child: RaisedButton( 41 | onPressed: (){ 42 | _showOptionSimpleDialog(); 43 | }, 44 | // 文本内容 45 | child: Text("showOptionSimpleDialog"), 46 | // 按钮颜色 47 | color: ThemeColors.colorTheme, 48 | )), 49 | Container( 50 | width: double.infinity,height: 50, 51 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 52 | child: RaisedButton( 53 | onPressed: (){ 54 | _showAlertDialog(); 55 | }, 56 | // 文本内容 57 | child: Text("showAlertDialog"), 58 | // 按钮颜色 59 | color: ThemeColors.colorTheme, 60 | )), 61 | Container( 62 | width: double.infinity,height: 50, 63 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 64 | child: RaisedButton( 65 | onPressed: (){ 66 | _showCustomUpdateDialog(); 67 | }, 68 | // 文本内容 69 | child: Text("showCustomUpdateDialog"), 70 | // 按钮颜色 71 | color: ThemeColors.colorTheme, 72 | )), 73 | Expanded( 74 | flex: 1, 75 | child: Container( 76 | alignment: Alignment.center, 77 | child: Text(alert,textAlign: TextAlign.center,), 78 | ), 79 | ), 80 | ],) 81 | ); 82 | } 83 | void _showToastDialog(){ 84 | new CommonDialog().showToastDialog(context, "您点击了:showToastDialog"); 85 | } 86 | void _showOptionSimpleDialog(){ 87 | if(EmptyUtil.listIsEmpty(strList)){ 88 | strList.add("内科"); 89 | strList.add("妇产科"); 90 | strList.add("神经科"); 91 | strList.add("耳鼻喉科"); 92 | strList.add("外科"); 93 | } 94 | new CommonDialog(onPressedOption: (result){ 95 | setState(() { 96 | alert = "您选择了:$result"; 97 | }); 98 | }).showOptionSimpleDialog(context, strList); 99 | } 100 | void _showAlertDialog(){ 101 | new CommonDialog(onPressedSure: (){ 102 | setState(() { 103 | alert = "您已成功预约山西第一人民医院-神经科的明天下午的挂号"; 104 | }); 105 | }).showAlertDialog(context, "您确定要预约山西第一人民医院 神经科的明天下午的挂号吗?"); 106 | } 107 | void _showCustomUpdateDialog(){ 108 | new CommonDialog(onPressedSure: (){ 109 | setState(() { 110 | alert = "正在更新..."; 111 | }); 112 | }).showCustomUpdateDialog(context,new UpdatePojo()); 113 | } 114 | } -------------------------------------------------------------------------------- /lib/third/agora/pages/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:permission_handler/permission_handler.dart'; 3 | import './call.dart'; 4 | 5 | class IndexPage extends StatefulWidget { 6 | @override 7 | State createState() { 8 | return new IndexState(); 9 | } 10 | } 11 | 12 | class IndexState extends State { 13 | /// create a channelController to retrieve text value 14 | final _channelController = TextEditingController(); 15 | 16 | /// if channel textfield is validated to have error 17 | bool _validateError = false; 18 | 19 | @override 20 | void dispose() { 21 | // dispose input controller 22 | _channelController.dispose(); 23 | super.dispose(); 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | appBar: AppBar( 30 | title: Text('Agora Flutter QuickStart'), 31 | ), 32 | body: Center( 33 | child: Container( 34 | padding: EdgeInsets.symmetric(horizontal: 20), 35 | height: 400, 36 | child: Column( 37 | children: [ 38 | Row(children: []), 39 | Row(children: [ 40 | Expanded( 41 | child: TextField( 42 | controller: _channelController, 43 | decoration: InputDecoration( 44 | errorText: _validateError 45 | ? "Channel name is mandatory" 46 | : null, 47 | border: UnderlineInputBorder( 48 | borderSide: BorderSide(width: 1)), 49 | hintText: 'Channel name'), 50 | )) 51 | ]), 52 | Padding( 53 | padding: EdgeInsets.symmetric(vertical: 20), 54 | child: Row( 55 | children: [ 56 | Expanded( 57 | child: RaisedButton( 58 | onPressed: () => onJoin(), 59 | child: Text("Join"), 60 | color: Colors.blueAccent, 61 | textColor: Colors.white, 62 | ), 63 | ) 64 | ], 65 | )) 66 | ], 67 | )), 68 | )); 69 | } 70 | 71 | onJoin() async { 72 | // update input validation 73 | setState(() { 74 | _channelController.text.isEmpty 75 | ? _validateError = true 76 | : _validateError = false; 77 | }); 78 | if (_channelController.text.isNotEmpty) { 79 | // await for camera and mic permissions before pushing video page 80 | bool getP = await _handleCameraAndMic(); 81 | 82 | // push video page with given channel name 83 | if(getP){ 84 | Navigator.push( 85 | context, 86 | MaterialPageRoute( 87 | builder: (context) => new CallPage( 88 | channelName: _channelController.text, 89 | ))); 90 | } 91 | } 92 | } 93 | List permissionList = [PermissionGroup.camera, PermissionGroup.microphone]; 94 | Future _handleCameraAndMic() async { 95 | bool getPerm = false; 96 | 97 | for(PermissionGroup p in permissionList){ 98 | /// 检查权限 99 | PermissionStatus permission = await PermissionHandler() 100 | .checkPermissionStatus(p); 101 | if(permission == PermissionStatus.granted){ 102 | getPerm = true; 103 | }else{ 104 | /// 请求权限 105 | Map permissions =await PermissionHandler() 106 | .requestPermissions([p]); 107 | if(permissions[p] == PermissionStatus.granted){ 108 | getPerm = true; 109 | }else{ 110 | getPerm = false; 111 | break; 112 | } 113 | } 114 | } 115 | return getPerm; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/agora/flutter_app1/utils/AppUtils.java: -------------------------------------------------------------------------------- 1 | package com.agora.flutter_app1.utils; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.content.pm.PackageManager.NameNotFoundException; 7 | import android.content.pm.Signature; 8 | 9 | import java.security.MessageDigest; 10 | import java.security.NoSuchAlgorithmException; 11 | import java.util.ArrayList; 12 | 13 | /** 14 | * 跟App相关的辅助类 15 | */ 16 | public class AppUtils { 17 | /** 18 | * 应用签名信息 19 | */ 20 | public final static String MD5 = "MD5"; 21 | public final static String SHA1 = "SHA1"; 22 | public final static String SHA256 = "SHA256"; 23 | 24 | /** 25 | * 返回一个签名的对应类型的字符串 26 | */ 27 | public static ArrayList getSingInfo(Context context, String packageName, String type) { 28 | ArrayList result = new ArrayList(); 29 | try { 30 | Signature[] signs = getSignatures(context, packageName); 31 | for (Signature sig : signs) { 32 | String tmp = "error!"; 33 | if (MD5.equals(type)) { 34 | tmp = getSignatureString(sig, MD5); 35 | } else if (SHA1.equals(type)) { 36 | tmp = getSignatureString(sig, SHA1); 37 | } else if (SHA256.equals(type)) { 38 | tmp = getSignatureString(sig, SHA256); 39 | } 40 | result.add(tmp); 41 | } 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } 45 | return result; 46 | } 47 | 48 | /** 49 | * 返回对应包的签名信息 50 | */ 51 | public static Signature[] getSignatures(Context context, String packageName) { 52 | PackageInfo packageInfo = null; 53 | try { 54 | packageInfo = 55 | context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES); 56 | return packageInfo.signatures; 57 | } catch (NameNotFoundException e) { 58 | e.printStackTrace(); 59 | } 60 | return null; 61 | } 62 | 63 | /** 64 | * 获取相应的类型的字符串(把签名的byte[]信息转换成16进制) 65 | */ 66 | public static String getSignatureString(Signature sig, String type) { 67 | byte[] hexBytes = sig.toByteArray(); 68 | String fingerprint = "error!"; 69 | try { 70 | MessageDigest digest = MessageDigest.getInstance(type); 71 | if (digest != null) { 72 | byte[] digestBytes = digest.digest(hexBytes); 73 | StringBuilder sb = new StringBuilder(); 74 | for (byte digestByte : digestBytes) { 75 | sb.append((Integer.toHexString((digestByte & 0xFF) | 0x100)).substring(1, 3)); 76 | } 77 | fingerprint = sb.toString(); 78 | } 79 | } catch (NoSuchAlgorithmException e) { 80 | e.printStackTrace(); 81 | } 82 | 83 | return fingerprint; 84 | } 85 | 86 | private AppUtils() { 87 | throw new UnsupportedOperationException("cannot be instantiated"); 88 | } 89 | 90 | /** 91 | * 获取应用程序名称 92 | */ 93 | public static String getAppName(Context context) { 94 | try { 95 | PackageManager packageManager = context.getPackageManager(); 96 | PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); 97 | int labelRes = packageInfo.applicationInfo.labelRes; 98 | return context.getResources().getString(labelRes); 99 | } catch (NameNotFoundException e) { 100 | e.printStackTrace(); 101 | } 102 | return null; 103 | } 104 | 105 | /** 106 | * [获取应用程序版本名称信息] 107 | * 108 | * @return 当前应用的版本名称 109 | */ 110 | public static String getVersionName(Context context) { 111 | try { 112 | PackageManager packageManager = context.getPackageManager(); 113 | PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); 114 | return packageInfo.versionName; 115 | } catch (NameNotFoundException e) { 116 | e.printStackTrace(); 117 | } 118 | return null; 119 | } 120 | 121 | /** 122 | * 获取应用版本号 123 | * 124 | * @return 当前应用版本 125 | */ 126 | public static int getVersionNumber(Context context) { 127 | try { 128 | PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 129 | return info.versionCode; 130 | } catch (NameNotFoundException e) { 131 | e.printStackTrace(); 132 | } 133 | return 1; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/agora/flutter_app1/my/MyWebviewActivity.java: -------------------------------------------------------------------------------- 1 | package com.agora.flutter_app1.my; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.Gravity; 6 | import android.webkit.JavascriptInterface; 7 | import android.webkit.WebView; 8 | import android.widget.LinearLayout; 9 | 10 | import com.agora.flutter_app1.my.channel.MyChannelUtil; 11 | import com.agora.flutter_app1.my.channel.MyMethodUtil; 12 | import com.agora.flutter_app1.utils.MyWebViewUtil; 13 | 14 | import java.util.Map; 15 | 16 | import io.flutter.plugin.common.BinaryMessenger; 17 | import io.flutter.plugin.common.MethodCall; 18 | import io.flutter.plugin.common.MethodChannel; 19 | 20 | public class MyWebviewActivity extends Activity { 21 | 22 | private WebView webView; 23 | String webUri; 24 | MethodChannel methodChannel; 25 | BinaryMessenger messenger; 26 | 27 | 28 | public MyWebviewActivity(BinaryMessenger messenger) { 29 | this.messenger = messenger; 30 | } 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT); 35 | LinearLayout lineLayout = new LinearLayout(this); 36 | lineLayout.setOrientation(LinearLayout.VERTICAL); 37 | lineLayout.setLayoutParams(params); 38 | lineLayout.setGravity(Gravity.TOP ); 39 | addView(lineLayout); 40 | setContentView(lineLayout); 41 | creatMethodChannel(); 42 | } 43 | private void addView(final LinearLayout lineLayout){ 44 | webView = new WebView(this); 45 | //添加文本到主布局 46 | lineLayout.addView(webView ); 47 | } 48 | private void setWebView(){ 49 | MyWebViewUtil myWebView = new MyWebViewUtil(); 50 | myWebView.setWebview(webView); 51 | webView.addJavascriptInterface(new JsInteraction(), "android"); 52 | webView.loadUrl(webUri); 53 | } 54 | /** 55 | * JS交互的类 56 | */ 57 | public class JsInteraction { 58 | 59 | //供Js调用的方法:在第一层HTML中返回到APP 60 | @JavascriptInterface 61 | public void returnApp(){ 62 | // finish(); 63 | } 64 | @JavascriptInterface 65 | public void startIdentifyFace(String idcardPic){ 66 | methodChannel.invokeMethod(MyMethodUtil.toFlutterFace,idcardPic); 67 | } 68 | @JavascriptInterface 69 | public void startIdentifyQRcode(String jsonStr){ 70 | methodChannel.invokeMethod(MyMethodUtil.toFlutterQRCode,jsonStr); 71 | } 72 | @JavascriptInterface 73 | public void startIdentifyIDCard(){ 74 | methodChannel.invokeMethod(MyMethodUtil.toFlutterIDCard,null); 75 | } 76 | } 77 | private void creatMethodChannel(){ 78 | // 直接 new MethodChannel,然后设置一个Callback来处理Flutter端调用 79 | methodChannel = new MethodChannel(messenger, MyChannelUtil.CHANNEL_start_custom_jpush); 80 | methodChannel.setMethodCallHandler( 81 | new MethodChannel.MethodCallHandler() { 82 | @Override 83 | public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { 84 | // 在这个回调里处理从Flutter来的调用 85 | String method = methodCall.method; 86 | switch (method){ 87 | case MyMethodUtil.getFlutterFaceResult: 88 | try { 89 | String result1 = (String) methodCall.arguments; 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | break; 94 | case MyMethodUtil.getFlutterIDCardResult: 95 | try { 96 | Map result2 = (Map) methodCall.arguments; 97 | idcardResult(result2.get("idCard"),result2.get("name"),result2.get("idCardUrl")); 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | } 101 | break; 102 | } 103 | } 104 | }); 105 | } 106 | private void idcardResult(String idcard_num,String idcard_name,String idcard_url){ 107 | webView.loadUrl("javascript: identifyIDCardResult('" + idcard_num + "','" + idcard_name + "','" + idcard_url + "')"); 108 | } 109 | private void faceResult(String result){ 110 | webView.loadUrl("javascript: ScanFaceWebs('" + result + "')"); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/agora/flutter_app1/utils/MyWebViewUtil.java: -------------------------------------------------------------------------------- 1 | package com.agora.flutter_app1.utils; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.util.Log; 7 | import android.webkit.CookieManager; 8 | import android.webkit.CookieSyncManager; 9 | import android.webkit.WebSettings; 10 | import android.webkit.WebView; 11 | import android.webkit.WebViewClient; 12 | 13 | 14 | import static android.content.ContentValues.TAG; 15 | 16 | /** 17 | * Created by Administrator on 2018-09-06. 18 | */ 19 | 20 | public class MyWebViewUtil { 21 | 22 | MyWebViewUtil myWebView; 23 | String APP_CACAHE_DIRNAME = "cache"; 24 | 25 | 26 | 27 | public MyWebViewUtil getInstance(){ 28 | if(myWebView == null){ 29 | myWebView = new MyWebViewUtil(); 30 | } 31 | return myWebView; 32 | } 33 | 34 | /** 35 | * webview的相关设置 36 | * @param webview 37 | */ 38 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 39 | public void setWebview(WebView webview){ 40 | 41 | webview.setHorizontalScrollBarEnabled(false);//水平滚动条不显示 42 | webview.setVerticalScrollBarEnabled(false); //垂直滚动条不显示 43 | 44 | webview.getSettings().setJavaScriptEnabled(true);//启用JavaScript 45 | webview.getSettings().setBlockNetworkImage(false);//解决图片不显示 46 | webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); 47 | //加载H5页面时,添加对一些标签的支持 48 | webview.getSettings().setLoadWithOverviewMode(true); //缩放至屏幕大小 49 | webview.getSettings().setUseWideViewPort(true); //将图片调整到适合webview的大小 50 | webview.getSettings().setSupportZoom(false); //是否支持缩放,默认为true。是下面那个的前提。 51 | webview.getSettings().setBuiltInZoomControls(false); //设置内置的缩放控件。若为false,则该WebView不可缩放 52 | webview.getSettings().setDisplayZoomControls(true); //隐藏原生缩放控件 53 | webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口 54 | webview.getSettings().setAllowFileAccess(true); //设置可以访问文件 55 | webview.getSettings().setDomStorageEnabled(true); 56 | if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) { 57 | webview.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); 58 | } 59 | webview.setWebViewClient(new WebViewClient() { 60 | @Override 61 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 62 | view.loadUrl(url); 63 | return super.shouldOverrideUrlLoading(view, url); 64 | } 65 | 66 | }); 67 | } 68 | 69 | @TargetApi(Build.VERSION_CODES.ECLAIR_MR1) 70 | public void setWebviewCache(WebView webview, Context context){ 71 | /*---------------------------------缓存的相关设置-----------------------------*/ 72 | webview.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); //设置 缓存模式 73 | // 开启 DOM storage API 功能 74 | webview.getSettings().setDomStorageEnabled(true); 75 | //开启 database storage API 功能 76 | webview.getSettings().setDatabaseEnabled(true); 77 | String cacheDirPath = FileUtils.getBasePath(context)+APP_CACAHE_DIRNAME; 78 | // String cacheDirPath = getCacheDir().getAbsolutePath()+Constant.APP_DB_DIRNAME; 79 | Log.i(TAG, "cacheDirPath="+cacheDirPath); 80 | //设置数据库缓存路径 webview.getSettings().setDatabasePath(cacheDirPath); 81 | //设置 Application Caches 缓存目录 82 | webview.getSettings().setAppCachePath(cacheDirPath); 83 | //开启 Application Caches 功能 84 | webview.getSettings().setAppCacheEnabled(true); 85 | } 86 | public void clearWebCache(WebView webView,Context context){ 87 | 88 | try { 89 | CookieSyncManager.createInstance(context); //Create a singleton CookieSyncManager within a context 90 | CookieManager cookieManager = CookieManager.getInstance(); // the singleton CookieManager instance 91 | cookieManager.removeAllCookie();// Removes all cookies. 92 | CookieSyncManager.getInstance().sync(); // forces sync manager to sync now 93 | 94 | webView.setWebChromeClient(null); 95 | webView.setWebViewClient(null); 96 | webView.getSettings().setJavaScriptEnabled(false); 97 | webView.clearCache(true); 98 | webView.stopLoading(); 99 | webView.clearHistory(); 100 | webView.loadUrl("about:blank"); 101 | webView.pauseTimers(); 102 | webView = null; 103 | } catch (Exception e) { 104 | e.printStackTrace(); 105 | } 106 | } 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/agora/flutter_app1/receiver/MyReceiver.java: -------------------------------------------------------------------------------- 1 | package com.agora.flutter_app1.receiver; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.text.TextUtils; 8 | 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | import java.util.Iterator; 13 | 14 | import cn.jpush.android.api.JPushInterface; 15 | 16 | /** 17 | * 自定义接收器 18 | * 19 | * 如果不定义这个 Receiver,则: 20 | * 1) 默认用户会打开主界面 21 | * 2) 接收不到自定义消息 22 | */ 23 | public class MyReceiver extends BroadcastReceiver { 24 | private static final String TAG = "JIGUANG-Example"; 25 | 26 | @Override 27 | public void onReceive(Context context, Intent intent) { 28 | try { 29 | Bundle bundle = intent.getExtras(); 30 | //Logger.d(TAG, "[MyReceiver] onReceive - " + intent.getAction() + ", extras: " + printBundle(bundle)); 31 | 32 | if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) { 33 | String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID); 34 | //Logger.d(TAG, "[MyReceiver] 接收Registration Id : " + regId); 35 | //send the Registration Id to your server... 36 | 37 | } else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) { 38 | //Logger.d(TAG, "[MyReceiver] 接收到推送下来的自定义消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE)); 39 | processCustomMessage(context, bundle); 40 | 41 | } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) { 42 | //Logger.d(TAG, "[MyReceiver] 接收到推送下来的通知"); 43 | int notifactionId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID); 44 | //Logger.d(TAG, "[MyReceiver] 接收到推送下来的通知的ID: " + notifactionId); 45 | 46 | } else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) { 47 | //Logger.d(TAG, "[MyReceiver] 用户点击打开了通知"); 48 | 49 | //打开自定义的Activity 50 | // Intent i = new Intent(context, TestActivity.class); 51 | // i.putExtras(bundle); 52 | // //i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 53 | // i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP ); 54 | // context.startActivity(i); 55 | 56 | } else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) { 57 | //Logger.d(TAG, "[MyReceiver] 用户收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA)); 58 | //在这里根据 JPushInterface.EXTRA_EXTRA 的内容处理代码,比如打开新的Activity, 打开一个网页等.. 59 | 60 | } else if(JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) { 61 | boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false); 62 | //Logger.w(TAG, "[MyReceiver]" + intent.getAction() +" connected state change to "+connected); 63 | } else { 64 | //Logger.d(TAG, "[MyReceiver] Unhandled intent - " + intent.getAction()); 65 | } 66 | } catch (Exception e){ 67 | 68 | } 69 | 70 | } 71 | 72 | // 打印所有的 intent extra 数据 73 | private static String printBundle(Bundle bundle) { 74 | StringBuilder sb = new StringBuilder(); 75 | for (String key : bundle.keySet()) { 76 | if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) { 77 | sb.append("\nkey:" + key + ", value:" + bundle.getInt(key)); 78 | }else if(key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)){ 79 | sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key)); 80 | } else if (key.equals(JPushInterface.EXTRA_EXTRA)) { 81 | if (TextUtils.isEmpty(bundle.getString(JPushInterface.EXTRA_EXTRA))) { 82 | //Logger.i(TAG, "This message has no Extra data"); 83 | continue; 84 | } 85 | 86 | try { 87 | JSONObject json = new JSONObject(bundle.getString(JPushInterface.EXTRA_EXTRA)); 88 | Iterator it = json.keys(); 89 | 90 | while (it.hasNext()) { 91 | String myKey = it.next(); 92 | sb.append("\nkey:" + key + ", value: [" + 93 | myKey + " - " +json.optString(myKey) + "]"); 94 | } 95 | } catch (JSONException e) { 96 | //Logger.e(TAG, "Get message extra JSON error!"); 97 | } 98 | 99 | } else { 100 | sb.append("\nkey:" + key + ", value:" + bundle.get(key)); 101 | } 102 | } 103 | return sb.toString(); 104 | } 105 | 106 | //send msg to MainActivity 107 | private void processCustomMessage(Context context, Bundle bundle) { 108 | /*if (MainActivity.isForeground) { 109 | String message = bundle.getString(JPushInterface.EXTRA_MESSAGE); 110 | String extras = bundle.getString(JPushInterface.EXTRA_EXTRA); 111 | Intent msgIntent = new Intent(MainActivity.MESSAGE_RECEIVED_ACTION); 112 | msgIntent.putExtra(MainActivity.KEY_MESSAGE, message); 113 | if (!ExampleUtil.isEmpty(extras)) { 114 | try { 115 | JSONObject extraJson = new JSONObject(extras); 116 | if (extraJson.length() > 0) { 117 | msgIntent.putExtra(MainActivity.KEY_EXTRAS, extras); 118 | } 119 | } catch (JSONException e) { 120 | 121 | } 122 | 123 | } 124 | LocalBroadcastManager.getInstance(context).sendBroadcast(msgIntent); 125 | }*/ 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /lib/start/sign_up_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:flutter_app1/fast/utils/style.dart' as theme; 4 | 5 | /** 6 | * 注册界面 7 | */ 8 | class SignUpPage extends StatefulWidget { 9 | @override 10 | _SignUpPageState createState() => new _SignUpPageState(); 11 | } 12 | 13 | class _SignUpPageState extends State { 14 | @override 15 | Widget build(BuildContext context) { 16 | return new Container( 17 | padding: EdgeInsets.only(top: 23), 18 | child: new Stack( 19 | alignment: Alignment.topCenter, 20 | overflow: Overflow.visible, 21 | children: [ 22 | new Container( 23 | decoration: new BoxDecoration( 24 | borderRadius: BorderRadius.all(Radius.circular(8)), 25 | color: Colors.white,), 26 | width: 300, 27 | height: 360, 28 | child: buildSignUpTextForm() 29 | ), 30 | 31 | new Positioned(child: new Center(child: 32 | new Container( 33 | padding: EdgeInsets.only( 34 | top: 10, bottom: 10, left: 42, right: 42), 35 | decoration: new BoxDecoration( 36 | gradient: theme.Theme.primaryGradient, 37 | borderRadius: BorderRadius.all(Radius.circular(5)), 38 | ), 39 | child: new Text("SignUp", 40 | style: new TextStyle(fontSize: 25, color: Colors.white),), 41 | ), 42 | ), top: 340,) 43 | 44 | ], 45 | ) 46 | ); 47 | } 48 | 49 | Widget buildSignUpTextForm() { 50 | return new Form(child: new Column( 51 | mainAxisSize: MainAxisSize.max, 52 | children: [ 53 | //用户名字 54 | Expanded( 55 | child: Padding( 56 | padding: const EdgeInsets.only( 57 | left: 25, right: 25, top: 20, bottom: 20), 58 | child: new TextFormField( 59 | decoration: new InputDecoration( 60 | icon: new Icon(FontAwesomeIcons.user, color: Colors.black,), 61 | hintText: "Name", 62 | border: InputBorder.none 63 | ), 64 | style: new TextStyle(fontSize: 16, color: Colors.black), 65 | ), 66 | ), 67 | ), 68 | new Container( 69 | height: 1, 70 | width: 250, 71 | color: Colors.grey[400], 72 | ), 73 | //邮箱 74 | Expanded( 75 | child: Padding( 76 | padding: const EdgeInsets.only( 77 | left: 25, right: 25, top: 20, bottom: 20), 78 | child: new TextFormField( 79 | decoration: new InputDecoration( 80 | icon: new Icon(Icons.email, color: Colors.black,), 81 | hintText: "Email Address", 82 | border: InputBorder.none 83 | ), 84 | style: new TextStyle(fontSize: 16, color: Colors.black), 85 | ), 86 | ), 87 | ), 88 | new Container( 89 | height: 1, 90 | width: 250, 91 | color: Colors.grey[400], 92 | ), 93 | //密码 94 | Expanded( 95 | child: Padding( 96 | padding: const EdgeInsets.only( 97 | left: 25, right: 25, top: 20, bottom: 20), 98 | child: new TextFormField( 99 | decoration: new InputDecoration( 100 | icon: new Icon(Icons.lock, color: Colors.black,), 101 | hintText: "Password", 102 | border: InputBorder.none, 103 | suffixIcon: new IconButton( 104 | icon: new Icon(Icons.remove_red_eye, color: Colors.black,), 105 | onPressed: () {}), 106 | ), 107 | obscureText: true, 108 | style: new TextStyle(fontSize: 16, color: Colors.black), 109 | ), 110 | ), 111 | ), 112 | new Container( 113 | height: 1, 114 | width: 250, 115 | color: Colors.grey[400], 116 | ), 117 | 118 | Expanded( 119 | child: Padding( 120 | padding: const EdgeInsets.only( 121 | left: 25, right: 25, top: 20, bottom: 20), 122 | child: new TextFormField( 123 | decoration: new InputDecoration( 124 | icon: new Icon(Icons.lock, color: Colors.black,), 125 | hintText: "Confirm Passowrd", 126 | border: InputBorder.none, 127 | suffixIcon: new IconButton( 128 | icon: new Icon(Icons.remove_red_eye, color: Colors.black,), 129 | onPressed: () {}), 130 | ), 131 | obscureText: true, 132 | style: new TextStyle(fontSize: 16, color: Colors.black), 133 | ), 134 | ), 135 | ), 136 | ], 137 | )); 138 | } 139 | 140 | } -------------------------------------------------------------------------------- /lib/fast/custom_widgets/custom_titlebar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | 4 | class CustomTitleBar extends StatefulWidget { 5 | final Key key; 6 | final double height; 7 | final CustomTitleBarController controller; 8 | final GestureTapCallback onMenuTap; 9 | final GestureTapCallback onMessageTap; 10 | 11 | CustomTitleBar({ 12 | this.onMenuTap, 13 | this.onMessageTap, 14 | this.controller, 15 | this.height: 80.0, 16 | this.key 17 | }) :super(key: key); 18 | 19 | @override 20 | State createState() { 21 | // TODO: implement createState 22 | return new CustomTitleBarState(); 23 | } 24 | } 25 | 26 | class CustomTitleBarState extends State { 27 | TextEditingController _textController = new TextEditingController(); 28 | CustomTitleBarController _controller; 29 | 30 | Widget _buildSearch() { 31 | Widget titleItem = null; 32 | titleItem = new Container( 33 | height: 80.0, 34 | alignment: Alignment.center, 35 | child: new Padding( 36 | padding: new EdgeInsets.only(top: 0.0), 37 | child: new Row( 38 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 39 | children: [ 40 | new Padding(padding: new EdgeInsets.only(left: 1.0)), 41 | new Container( 42 | height: 35.0, 43 | width: 200.0, 44 | child: new Material( 45 | color: Colors.white70, 46 | borderRadius: new BorderRadius.horizontal( 47 | left: new Radius.circular(20.0), 48 | right: new Radius.circular(20.0)), 49 | child: new Padding( 50 | padding: new EdgeInsets.only(right: 5.0), 51 | child: new Row( 52 | children: [ 53 | new Padding( 54 | padding: new EdgeInsets.only(left: 5.0)), 55 | new Icon( 56 | Icons.search, 57 | color: const Color(0xFF616161)), 58 | new Padding( 59 | padding: new EdgeInsets.only(left: 3.0)), 60 | new Flexible(child: new TextField( 61 | maxLines: 1, 62 | controller: _textController, 63 | onChanged: (v) { 64 | // _handleOnSeachChange(); 65 | }, 66 | onSubmitted: (v) { 67 | // _handleOnSeachChange(); 68 | }, 69 | style: new TextStyle( 70 | color: const Color(0xFF616161), 71 | fontSize: 14.0), 72 | decoration: new InputDecoration.collapsed( 73 | hintText: "请输入关键字"), 74 | ), 75 | ), 76 | ], 77 | ),) 78 | ), 79 | ), 80 | new Padding(padding: new EdgeInsets.only(left: 1.0)), 81 | ], 82 | ),), 83 | ); 84 | return titleItem; 85 | } 86 | 87 | _buildTitle() { 88 | Widget mWidget = null; 89 | mWidget = new Container( 90 | height: widget.height, 91 | color: new Color.fromARGB(_controller.value.alpha, 25, 112, 183), 92 | child: new Padding(padding: new EdgeInsets.only(top: 25.0), 93 | child: new Row( 94 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 95 | children: [ 96 | new Padding(padding: new EdgeInsets.only(right: 5.0)), 97 | 98 | new GestureDetector( 99 | onTap: widget.onMenuTap==null?(){}: widget.onMenuTap, 100 | child: new InkWell( 101 | child: new Icon( 102 | Icons.format_list_bulleted, color: Colors.white), 103 | ), 104 | ), 105 | _buildSearch(), 106 | new GestureDetector( 107 | onTap: widget.onMessageTap==null?(){}: widget.onMessageTap, 108 | child: new InkWell( 109 | 110 | child: new Icon(Icons.message, color: Colors.white), 111 | ), 112 | ), 113 | new Padding(padding: new EdgeInsets.only(right: 5.0)), 114 | ], 115 | ),), 116 | ); 117 | return mWidget; 118 | } 119 | 120 | 121 | @override 122 | Widget build(BuildContext context) { 123 | if (widget.controller == null) { 124 | _controller = new CustomTitleBarController(); 125 | _controller.value.alpha = 0; 126 | } else { 127 | _controller = widget.controller; 128 | } 129 | return _buildTitle(); 130 | } 131 | } 132 | 133 | 134 | class CustomTitleBarController extends ValueNotifier { 135 | CustomTitleBarController() :super(new ContomTitleAlphaValue()); 136 | } 137 | 138 | class ContomTitleAlphaValue { 139 | int alpha; 140 | } -------------------------------------------------------------------------------- /lib/start/titlebardemo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app1/fast/custom_widgets/custom_titlebar.dart'; 3 | class TitleBarGradient extends StatefulWidget { 4 | @override 5 | State createState() { 6 | // TODO: implement createState 7 | return new _TitleBarGradientState(); 8 | } 9 | } 10 | class _TitleBarGradientState extends State { 11 | ScrollController _mScrollController = new ScrollController(); 12 | GlobalKey_mTitleKey = new GlobalKey(); 13 | CustomTitleBarController _mCustomTitleBarController = new CustomTitleBarController(); 14 | bool _isNeedSetAlpha = false; 15 | @override 16 | void initState() { 17 | super.initState(); 18 | _mCustomTitleBarController.value.alpha = 0; 19 | _mScrollController.addListener(() { 20 | if (_mScrollController.offset < 80.0) { 21 | _isNeedSetAlpha = true; 22 | _mCustomTitleBarController.value.alpha = 23 | ((_mScrollController.offset / 80) * 255).toInt(); 24 | _mTitleKey.currentState.setState(() {}); 25 | } else { 26 | if (_isNeedSetAlpha) { 27 | _mCustomTitleBarController.value.alpha = 255; 28 | _mTitleKey.currentState.setState(() {}); 29 | _isNeedSetAlpha = false; 30 | } 31 | } 32 | }); 33 | } 34 | Widget build(BuildContext context) { 35 | return new Scaffold( 36 | body: new Stack( 37 | children: [ 38 | new Container( 39 | height: MediaQuery.of(context).size.height, 40 | child: new Listener( 41 | onPointerDown: (dd) {}, 42 | onPointerMove: (sss) {}, 43 | onPointerUp: (ss) {}, 44 | onPointerCancel: (s) {}, 45 | child: new SingleChildScrollView( 46 | controller: _mScrollController, 47 | child: new Column( 48 | children: [ 49 | new Container( 50 | color: Colors.red, 51 | height: 200.0, 52 | child: new Center(child: new Text("内容1"),), 53 | ), 54 | new Container( 55 | height: 200.0, 56 | child: new Center(child: new Text("内容2"),), 57 | ), 58 | new Container( 59 | height: 200.0, 60 | child: new Center(child: new Text("内容3"),), 61 | ), 62 | new Container( 63 | height: 200.0, 64 | child: new Center(child: new Text("内容4"),), 65 | ), 66 | new Container( 67 | height: 200.0, 68 | child: new Center(child: new Text("dasdasdasdasd"),), 69 | ), new Container( 70 | height: 200.0, 71 | child: new Center(child: new Text("dasdasdasdasd"),), 72 | ), new Container( 73 | height: 200.0, 74 | child: new Center(child: new Text("dasdasdasdasd"),), 75 | ) 76 | ], 77 | ), 78 | ), 79 | ), 80 | ), 81 | new CustomTitleBar( 82 | height: 80.0, 83 | controller: _mCustomTitleBarController, 84 | key: _mTitleKey, 85 | ), 86 | ], 87 | ), 88 | ); 89 | } 90 | /*Widget _buildCustomBtn(){ 91 | return LikeButton( 92 | size: 60, 93 | circleColor: 94 | CircleColor(start: Color(0xff00ddff), end: Color(0xff0099cc)), 95 | bubblesColor: BubblesColor( 96 | dotPrimaryColor: Color(0xff33b5e5), 97 | dotSecondaryColor: Color(0xff0099cc), 98 | ), 99 | likeBuilder: (bool isLiked) { 100 | return Icon( 101 | Icons.home, 102 | color: isLiked ? Colors.deepPurpleAccent : Colors.grey, 103 | size: buttonSize, 104 | ); 105 | }, 106 | likeCount: 665, 107 | countBuilder: (int count, bool isLiked, String text) { 108 | var color = isLiked ? Colors.deepPurpleAccent : Colors.grey; 109 | Widget result; 110 | if (count == 0) { 111 | result = Text( 112 | "love", 113 | style: TextStyle(color: color), 114 | ); 115 | } else 116 | result = Text( 117 | text, 118 | style: TextStyle(color: color), 119 | ); 120 | return result; 121 | }, 122 | ); 123 | 124 | }*/ 125 | /*Future onLikeButtonTap(bool isLiked, TuChongItem item) { 126 | ///send your request here 127 | /// 128 | final Completer completer = new Completer(); 129 | Timer(const Duration(milliseconds: 200), () { 130 | item.isFavorite = !item.isFavorite; 131 | item.favorites = 132 | item.isFavorite ? item.favorites + 1 : item.favorites - 1; 133 | 134 | // if your request is failed,return null, 135 | completer.complete(item.isFavorite); 136 | }); 137 | return completer.future; 138 | }*/ 139 | 140 | } 141 | -------------------------------------------------------------------------------- /lib/home/page/camera/example_camera.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:camera/camera.dart'; 5 | import 'package:fluttertoast/fluttertoast.dart'; 6 | import 'package:path_provider/path_provider.dart'; 7 | final GlobalKey _scaffoldKey = GlobalKey(); 8 | 9 | List cameras; 10 | 11 | Future getCameras(BuildContext context) async { 12 | cameras = await availableCameras(); 13 | runApp(CameraApp()); 14 | //return _CameraAppState(); 15 | } 16 | 17 | class CameraApp extends StatefulWidget { 18 | 19 | @override 20 | _CameraAppState createState() => _CameraAppState(); 21 | } 22 | 23 | class _CameraAppState extends State { 24 | CameraController controller; 25 | String imagePath; 26 | @override 27 | void initState() { 28 | super.initState(); 29 | if(cameras != null){ 30 | controller = CameraController(cameras[0], ResolutionPreset.medium); 31 | controller.initialize().then((_) { 32 | if (!mounted) { 33 | return; 34 | } 35 | setState(() {}); 36 | }); 37 | } 38 | } 39 | 40 | @override 41 | void dispose() { 42 | controller?.dispose(); 43 | super.dispose(); 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | if (!controller.value.isInitialized) { 49 | return Container(); 50 | } 51 | return new MaterialApp( 52 | 53 | home: new Scaffold( 54 | body: new Builder(builder: (BuildContext context){ 55 | return Container( 56 | child: AspectRatio( 57 | aspectRatio: 58 | controller.value.aspectRatio, 59 | child: CameraPreview(controller)), 60 | foregroundDecoration: BoxDecoration( 61 | image: DecorationImage( 62 | image: ExactAssetImage('assets/images/bg_identify_head.png'), 63 | fit: BoxFit.scaleDown, 64 | ), 65 | ), 66 | ); 67 | 68 | 69 | // return new Scaffold( 70 | // body: AspectRatio( 71 | // aspectRatio: 72 | // controller.value.aspectRatio, 73 | // child: CameraPreview(controller)), 74 | // /*floatingActionButton:new FloatingActionButton( 75 | // foregroundColor: Colors.white, 76 | // elevation: 10.0, 77 | // onPressed: () {}, 78 | // child: new Image.asset('assets/images/bg_identify_head.png'), 79 | // ), 80 | // floatingActionButtonLocation:FloatingActionButtonLocation.centerFloat,*/ 81 | // ); 82 | 83 | 84 | }), 85 | floatingActionButton: new FloatingActionButton( 86 | foregroundColor: Colors.white, 87 | elevation: 10.0, 88 | onPressed: controller != null && 89 | controller.value.isInitialized && 90 | !controller.value.isRecordingVideo 91 | ? onTakePictureButtonPressed 92 | : null, 93 | child: new Image.asset('assets/images/ic_take_photo.png'), 94 | ), 95 | floatingActionButtonLocation:FloatingActionButtonLocation.centerFloat, 96 | ), 97 | ); 98 | /*return AspectRatio( 99 | aspectRatio: 100 | controller.value.aspectRatio, 101 | child: CameraPreview(controller));*/ 102 | } 103 | void onTakePictureButtonPressed() { 104 | takePicture().then((String filePath) { 105 | if (mounted) { 106 | setState(() { 107 | imagePath = filePath; 108 | //videoController?.dispose(); 109 | //videoController = null; 110 | }); 111 | if (filePath != null) showInSnackBar('Picture saved to $filePath'); 112 | } 113 | }); 114 | } 115 | Future takePicture() async { 116 | if (!controller.value.isInitialized) { 117 | showInSnackBar('Error: select a camera first.'); 118 | return null; 119 | } 120 | final Directory extDir = await getApplicationDocumentsDirectory(); 121 | final String dirPath = '${extDir.path}/Pictures/flutter_test'; 122 | await Directory(dirPath).create(recursive: true); 123 | final String filePath = '$dirPath/${timestamp()}.jpg'; 124 | 125 | if (controller.value.isTakingPicture) { 126 | // A capture is already pending, do nothing. 127 | return null; 128 | } 129 | 130 | try { 131 | await controller.takePicture(filePath); 132 | } on CameraException catch (e) { 133 | showInSnackBar(e.toString()); 134 | return null; 135 | } 136 | return filePath; 137 | } 138 | void showInSnackBar(String message) { 139 | _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message))); 140 | } 141 | String timestamp() => DateTime.now().millisecondsSinceEpoch.toString(); 142 | 143 | Future startVideoRecording() async { 144 | if (!controller.value.isInitialized) { 145 | //showInSnackBar('Error: select a camera first.'); 146 | Fluttertoast.showToast(msg: "'Error: select a camera first."); 147 | return null; 148 | } 149 | 150 | final Directory extDir = await getApplicationDocumentsDirectory(); 151 | final String dirPath = '${extDir.path}/Movies/flutter_test'; 152 | await Directory(dirPath).create(recursive: true); 153 | final String filePath = '$dirPath/${timestamp()}.mp4'; 154 | 155 | if (controller.value.isRecordingVideo) { 156 | // A recording is already started, do nothing. 157 | return null; 158 | } 159 | 160 | try { 161 | //videoPath = filePath; 162 | await controller.startVideoRecording(filePath); 163 | } on CameraException catch (e) { 164 | //_showCameraException(e); 165 | return null; 166 | } 167 | return filePath; 168 | } 169 | } -------------------------------------------------------------------------------- /lib/fast/utils/style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app1/fast/utils/value.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | 5 | 6 | //文本设置 7 | class AppStyle{ 8 | 9 | /*------------------------------------------------TextStyle-----------------------------------------------------*/ 10 | /// 字体:#666 16 11 | static var inputTextKey1 = TextStyle( 12 | color: ThemeColors.color666666, 13 | fontSize: TextSize.add6, 14 | ); 15 | 16 | /// 字体:#333 16 17 | static var inputText1 = TextStyle( 18 | color: ThemeColors.color333333, 19 | fontSize: TextSize.add6, 20 | ); 21 | /// 字体:#333 16 w700 22 | static var itemTitleText1 = TextStyle( 23 | color: ThemeColors.color333333, 24 | fontSize: TextSize.add16, 25 | fontWeight: FontWeight.w700 26 | ); 27 | /// 字体:#666 14 28 | static var dialogKeyText1 = TextStyle( 29 | color: ThemeColors.color666666, 30 | fontSize: TextSize.add4, 31 | ); 32 | /// 字体:#666 12 33 | static var textStyle12_c6 = TextStyle( 34 | color: ThemeColors.color666666, 35 | fontSize: TextSize.add2, 36 | ); 37 | /// 字体:#333 12 38 | static var textStyle12_c3 = TextStyle( 39 | color: ThemeColors.color333333, 40 | fontSize: TextSize.add2, 41 | ); 42 | /// 字体:#666 16 w300 43 | static var dialogKeyText2 = TextStyle( 44 | color: ThemeColors.color666666, 45 | fontSize: TextSize.add6, 46 | fontWeight: FontWeight.w300 47 | ); 48 | /// 字体:#333 24 w300 49 | static var dialogKeyText3 = TextStyle( 50 | color: ThemeColors.color333333, 51 | fontSize: TextSize.add14, 52 | fontWeight: FontWeight.w300 53 | ); 54 | /// 字体:#333 14 w300 55 | static var dialogValueText1 = TextStyle( 56 | color: ThemeColors.color333333, 57 | fontSize: TextSize.add4, 58 | fontWeight: FontWeight.w300 59 | ); 60 | /// 字体:#fff 18 w500 61 | static var buttonText1 = TextStyle( 62 | color: ThemeColors.colorWhite, 63 | fontSize: TextSize.add8, 64 | fontWeight: FontWeight.w500 65 | ); 66 | /// 字体:#666 16 w300 67 | static var buttonText2 = TextStyle( 68 | color: ThemeColors.color666666, 69 | fontSize: TextSize.add6, 70 | fontWeight: FontWeight.w300 71 | ); 72 | /*-----------------------------------------RoundedRectangleBorder-------------------------------------------------------------------------*/ 73 | static var buttonStyle1 = RoundedRectangleBorder( 74 | side: BorderSide( // 保留原来的边框样式 75 | width: 0, 76 | color: ThemeColors.colorDDDDDD, 77 | style: BorderStyle.solid, 78 | ), 79 | borderRadius: BorderRadius.all(Radius.circular(50)), 80 | ); 81 | /// button 圆角矩形(6) 边框(#999 宽-0.5) 82 | static var btnStyle_grey_line = RoundedRectangleBorder( 83 | side: BorderSide( // 保留原来的边框样式 84 | width: 0.5, 85 | color: ThemeColors.color999999, 86 | style: BorderStyle.solid, 87 | ), 88 | borderRadius: BorderRadius.all(Radius.circular(6)), 89 | ); 90 | /*------------------------------------------BoxDecoration----------------------------------------------------------------------------*/ 91 | /// layout 半椭圆(15.0) 92 | static var layoutStyle_noline = new BoxDecoration( 93 | //border: new Border.all(color: Color(0xFFFF0000), width: 0.5), // 边色与边宽度 94 | color: ThemeColors.colorEEEEEE, // 底色 95 | borderRadius: new BorderRadius.circular((28.0)), // 圆角度 96 | //borderRadius: new BorderRadius.vertical(top: Radius.elliptical(20, 50)), // 也可控件一边圆角大小 97 | ); 98 | /*-----------------------------------------------------------------------------------------------------------------*/ 99 | static InputDecoration getSearchInputDec(String alert){ 100 | return InputDecoration( 101 | hintText:alert ,// 提示文本内容 102 | border:InputBorder.none, 103 | fillColor: ThemeColors.transparent,//设置背景色 104 | filled: true, 105 | contentPadding: const EdgeInsets.symmetric(vertical: 8),// 可控制高度 106 | ); 107 | } 108 | static TextStyle getTextStyle_28_a(BuildContext c){ 109 | return TextStyle( 110 | color: ThemeColors.colorAAA,// 文本(字体)颜色 111 | fontSize: ScreenUtil().setSp(TextSize.font_h),// 字体大小 112 | ); 113 | } 114 | static TextStyle getTextStyle_32_3(BuildContext c){ 115 | return TextStyle( 116 | color: ThemeColors.color333333,// 文本(字体)颜色 117 | fontSize: ScreenUtil().setSp(TextSize.font_xxh),// 字体大小 118 | ); 119 | } 120 | static TextStyle getTextStyle_30_6(BuildContext c){ 121 | return TextStyle( 122 | color: ThemeColors.color666666,// 文本(字体)颜色 123 | fontSize: ScreenUtil().setSp(TextSize.font_xh),// 字体大小 124 | ); 125 | } 126 | static TextStyle getTextStyle_36_3(BuildContext c){ 127 | return TextStyle( 128 | color: ThemeColors.color333333,// 文本(字体)颜色 129 | fontSize: ScreenUtil().setSp(TextSize.font_xxxh),// 字体大小 130 | ); 131 | } 132 | static TextStyle getTextStyle_30_9(BuildContext c){ 133 | return TextStyle( 134 | color: ThemeColors.color999999,// 文本(字体)颜色 135 | fontSize: ScreenUtil().setSp(TextSize.font_xh),// 字体大小 136 | ); 137 | } 138 | } 139 | 140 | class WidgetDemoColor { 141 | static const int fontColor = 0xFF607173; 142 | static const int iconColor = 0xFF607173; 143 | static const int borderColor = 0xFFEFEFEF; 144 | 145 | } 146 | class Theme { 147 | 148 | /** 149 | * 登录界面,定义渐变的颜色 150 | */ 151 | /* static const Color loginGradientStart = const Color(0xFFF9986B); 152 | static const Color loginGradientEnd = const Color(0xFFF7438C);*/ 153 | 154 | static const Color loginGradientStart = const Color(0xFFD1EAAC); 155 | static const Color loginGradientEnd = const Color(0xFF51D7C9); 156 | 157 | static const LinearGradient primaryGradient = const LinearGradient( 158 | colors: const [loginGradientStart, loginGradientEnd], 159 | stops: const [0.0, 1.0], 160 | begin: Alignment.topCenter, 161 | end: Alignment.bottomCenter, 162 | ); 163 | } -------------------------------------------------------------------------------- /lib/home/page/home/home.dart: -------------------------------------------------------------------------------- 1 | //import 'package:camera/camera.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_app1/fast/constants/constant.dart'; 4 | import 'package:flutter_app1/home/page/camera/example_camera.dart'; 5 | import 'package:flutter_app1/home/page/camera/identify_card.dart'; 6 | //import 'package:flutter_app1/home/page/custom_camera.dart'; 7 | //import 'package:flutter_app1/home/page/example_camera.dart'; 8 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 9 | import 'package:fluttertoast/fluttertoast.dart'; 10 | 11 | class HomePage extends StatefulWidget{ 12 | @override 13 | State createState() { 14 | return _HomePageState(); 15 | } 16 | } 17 | 18 | class _HomePageState extends State{ 19 | //https://www.cnblogs.com/pjl43/p/9866753.html 20 | //https://blog.csdn.net/qq_39347285/article/details/86219020 21 | //https://www.jianshu.com/p/f87044ebe9e7 22 | FlutterWebviewPlugin flutterWebviewPlugin = FlutterWebviewPlugin(); 23 | var webUrl = "http://192.168.2.55:8020/XF%E9%A1%B9%E7%9B%AE/login.html"; 24 | var webUrl1= "assets/xf_demo/login.html"; 25 | var webUrl2; 26 | @override 27 | Widget build(BuildContext context) { 28 | 29 | /*return new MaterialApp( 30 | routes: { 31 | "/": (_) => new WebviewScaffold( 32 | url: "https://www.baidu.com", 33 | appBar: new AppBar( 34 | title: new Text("退役军人信访"), 35 | ), 36 | ) 37 | }, 38 | );*/ 39 | /*return new SafeArea( 40 | top: true, 41 | child: WebviewScaffold( 42 | url:webUrl, 43 | withZoom: false, 44 | withLocalStorage: true, 45 | withJavascript: true, 46 | ), 47 | );*/ 48 | return Scaffold( 49 | body: SafeArea( 50 | top: true, 51 | child: WebviewScaffold( 52 | url:webUrl, 53 | withZoom: false, 54 | withLocalStorage: true, 55 | withJavascript: true, 56 | ), 57 | ), 58 | backgroundColor: Colors.white, 59 | ); 60 | /*return Scaffold( 61 | // 默认时沉浸式 62 | backgroundColor: Colors.white, 63 | body: WebviewScaffold( 64 | url:webUrl, 65 | withZoom: false, 66 | withLocalStorage: true, 67 | withJavascript: true, 68 | ), 69 | );*/ 70 | } 71 | @override 72 | void initState() { 73 | flutterWebviewPlugin.onStateChanged.listen((WebViewStateChanged state){ 74 | switch(state.type){ 75 | case WebViewState.shouldStart: 76 | //准备加载 77 | print("准备加载"); 78 | break; 79 | case WebViewState.startLoad: 80 | //开始加载 81 | print("开始加载"); 82 | break; 83 | case WebViewState.finishLoad: 84 | //加载完成 85 | print("加载完成"); 86 | //loginWebSuccess(); 87 | //identifyIDCardResult(); 88 | break; 89 | case WebViewState.abortLoad: 90 | print("abortLoad"); 91 | break; 92 | } 93 | }); 94 | flutterWebviewPlugin.onUrlChanged.listen((String url){ 95 | String nowUrl = url; 96 | if(nowUrl.contains("findPassword")){ 97 | toCustomCamera(context, ConstantKey.camera_identify_face); 98 | } 99 | }); 100 | flutterWebviewPlugin.onDestroy.listen((Null){ 101 | print("onDestroy"); 102 | 103 | }); 104 | flutterWebviewPlugin.onHttpError.listen((WebViewHttpError error){ 105 | print("onHttpError"); 106 | }); 107 | } 108 | /*JavascriptChannel _alertJavascriptChannel(BuildContext context) { 109 | return JavascriptChannel( 110 | name: 'Toast', 111 | onMessageReceived: (JavascriptMessage message) { 112 | showToast(message.message); 113 | }); 114 | }*/ 115 | startIdentifyFace(String message){ 116 | //startActivity(new Intent(StartWebActivity.this, IdentifyVideoActivity.class)); 117 | Fluttertoast.showToast(msg: "开始识别人脸"); 118 | } 119 | startIdentifyQRcode(String message){ 120 | //startActivity(new Intent(StartWebActivity.this, IdentifyQRcodeActivity.class)); 121 | Fluttertoast.showToast(msg: "开始识别二维码"); 122 | } 123 | Future startIdentifyIDCard() async { 124 | //CommonField.init("RegistIDCardCollectFragment", "信息采集", false); 125 | //startActivity(new Intent(StartWebActivity.this, CommonActivity.class)); 126 | Fluttertoast.showToast(msg: "开始识别身份证"); 127 | Map result = await Navigator .of(context) .push( 128 | new MaterialPageRoute(builder: (context) { 129 | //return new IdentifyCardIndex(); 130 | })); 131 | if(result != null){ 132 | identifyIDCardResult(result[ConstantKey.IDCARD_NUM],result[ConstantKey.IDCARD_NAME]); 133 | } 134 | } 135 | 136 | void loginWebSuccess() { 137 | flutterWebviewPlugin.evalJavascript("loginWebSuccess();"); 138 | } 139 | 140 | void identifyIDCardResult(var card,var name) { 141 | var idcard_num = "140401199603032641"; 142 | var idcard_name = "彭昭慧"; 143 | flutterWebviewPlugin.evalJavascript("identifyIDCardResult('" + card + "','" + name + "');"); 144 | } 145 | @override void dispose() { 146 | // 回收相关资源 147 | // Every listener should be canceled, the same should be done with this stream. 148 | //onUrlChanged.cancel(); 149 | //onStateChanged.cancel(); 150 | flutterWebviewPlugin.dispose(); 151 | super.dispose(); 152 | } 153 | 154 | toCustomCamera(BuildContext context,int cameraType){ 155 | //return CameraApp(); 156 | getCameras(context); 157 | 158 | // pushAndRemoveUntil方式:跳转到下个页面,并且销毁当前页面 159 | //push方法:直接跳转到下个页面,可以传递参数 160 | /*Navigator.push( 161 | context, 162 | new MaterialPageRoute( 163 | builder: (context) => new CustomCameraPage(cameraType) 164 | ), 165 | );*/ 166 | } 167 | /*List cameras; 168 | Future getCameras() async { 169 | cameras = await availableCameras(); 170 | runApp(CameraApp(cameras)); 171 | }*/ 172 | } 173 | 174 | -------------------------------------------------------------------------------- /lib/third/agora/pages/index3.dart: -------------------------------------------------------------------------------- 1 | import 'package:agora_rtm/agora_rtm.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_app1/fast/constants/constant.dart'; 5 | import 'package:flutter_app1/fast/utils/permission.dart'; 6 | import 'package:flutter_app1/third/agora/pages/videocall.dart'; 7 | import 'package:flutter_app1/third/agora/utils/agora_utils.dart'; 8 | import 'package:flutter_app1/fast/utils/empty.dart'; 9 | import 'package:flutter_app1/fast/utils/value.dart'; 10 | import 'package:fluttertoast/fluttertoast.dart'; 11 | import 'package:permission_handler/permission_handler.dart'; 12 | 13 | class AgoraCustomPage extends StatefulWidget { 14 | @override 15 | createState() => new AgoraCustomState(); 16 | } 17 | 18 | class AgoraCustomState extends State { 19 | TextEditingController _friendController = new TextEditingController(); 20 | TextEditingController _groupController = new TextEditingController(); 21 | String _channelName = "agora"; 22 | AgoraRtmClient _client; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | initAgoraRtm(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return new Scaffold( 33 | appBar: new AppBar( 34 | title: new Text("声网"), 35 | ), 36 | body: buildStartPage(), 37 | ); 38 | } 39 | Widget buildStartPage(){ 40 | return SingleChildScrollView( 41 | child: ConstrainedBox(// 添加额外为限制条件到child,如最小/大宽度、高度。。。 42 | constraints: BoxConstraints( 43 | minHeight: 120.0, 44 | ), 45 | child: Column(children: [ 46 | Container( 47 | width: double.infinity, 48 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 49 | child: TextField( 50 | controller: _friendController, 51 | autofocus: false, 52 | decoration: InputDecoration( 53 | icon: Icon(Icons.person), 54 | labelText: '请输入好友id', 55 | helperText: '请正确输入好友的id', 56 | ), 57 | ) 58 | ), 59 | Container( 60 | width: double.infinity, 61 | height: 50, 62 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 63 | child: RaisedButton( 64 | onPressed: (){ 65 | clickFriendVideo(); 66 | }, 67 | // 文本内容 68 | child: Text("和好友视频通话"), 69 | // 按钮颜色 70 | color: ThemeColors.colorTheme, 71 | )), 72 | Container( 73 | width: double.infinity, 74 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 75 | child: TextField( 76 | controller: _groupController, 77 | autofocus: false, 78 | decoration: InputDecoration( 79 | icon: Icon(Icons.group), 80 | labelText: '请输入群id', 81 | helperText: '请输入群视频的通道id', 82 | ), 83 | ) 84 | ), 85 | Container( 86 | width: double.infinity, 87 | height: 50, 88 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 89 | child: RaisedButton( 90 | onPressed: (){ 91 | clickGroupVideo(); 92 | }, 93 | // 文本内容 94 | child: Text("加入群视频通话"), 95 | // 按钮颜色 96 | color: ThemeColors.colorTheme, 97 | )), 98 | /*GestureDetector( 99 | onTap: testTap, 100 | child:Align( 101 | alignment: Alignment.center, 102 | child: Container( 103 | width: 100.0, 104 | height: 50, 105 | margin: const EdgeInsets.fromLTRB(20,30,20,0), 106 | color: ThemeColors.colorTheme, 107 | child: Column(children: [ 108 | Text("测试点击事件") 109 | ],) 110 | ), 111 | ) , 112 | ),*/ 113 | ]),), 114 | ); 115 | } 116 | void testTap(){ 117 | Fluttertoast.showToast(msg: "点击响应"); 118 | } 119 | Future clickFriendVideo() async { 120 | List permissionList = [PermissionGroup.camera, PermissionGroup.microphone]; 121 | bool getPerm = await PermissionUtil.handlePermission(permissionList); 122 | if(getPerm){ 123 | if(EmptyUtil.textIsEmpty(_friendController.text)){ 124 | Fluttertoast.showToast(msg: "Friend id cannot be empty"); 125 | }else{ 126 | _callVideo(_friendController.text); 127 | } 128 | }else{ 129 | Fluttertoast.showToast(msg: "请授权相关权限"); 130 | } 131 | } 132 | Future _callVideo(String peerId) async { 133 | 134 | if(_client != null){ 135 | bool online =await AgoraUtils.queryPeerOnlineStatus(_client, peerId); 136 | if(online){ 137 | try{ 138 | _channelName = ConstantObject.getUser().agoraId+peerId; 139 | String msg = AgoraUtils.getAgoraMsgType(1)+","+_channelName; 140 | await _client.sendMessageToPeer(peerId, AgoraRtmMessage(msg)); 141 | Navigator.push(context, new MaterialPageRoute( 142 | builder: (BuildContext context) { 143 | return new VideoCallPage(_channelName,peerId); 144 | })); 145 | }catch(e){ 146 | print(e.toString()); 147 | } 148 | }else{ 149 | Fluttertoast.showToast(msg: "The friend is offline"); 150 | } 151 | } 152 | } 153 | void clickGroupVideo(){ 154 | if(EmptyUtil.textIsEmpty(_groupController.text)){ 155 | Fluttertoast.showToast(msg: "Group id cannot be empty"); 156 | }else{ 157 | 158 | } 159 | } 160 | Future initAgoraRtm() async { 161 | _client =await AgoraUtils.getAgoraRtmClient(); 162 | } 163 | } -------------------------------------------------------------------------------- /lib/home/page/camera/identify_qrcode.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:camera/camera.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:path_provider/path_provider.dart'; 7 | import 'package:video_player/video_player.dart'; 8 | import 'package:dio/dio.dart'; 9 | import 'package:flutter_app1/fast/constants/constant.dart'; 10 | import 'package:flutter_image_compress/flutter_image_compress.dart'; 11 | import 'package:path_provider/path_provider.dart' as path_provider; 12 | import 'camera_pojo.dart'; 13 | 14 | class IdentifyQRCode extends StatefulWidget { 15 | 16 | List _cameras; 17 | 18 | IdentifyQRCode(this._cameras){ 19 | cameras = _cameras; 20 | } 21 | 22 | @override 23 | _IdentifyQRCodeState createState() { 24 | return _IdentifyQRCodeState(); 25 | } 26 | } 27 | 28 | 29 | void logError(String code, String message) => 30 | print('Error: $code\nError Message: $message'); 31 | 32 | class _IdentifyQRCodeState extends State { 33 | CameraController controller; 34 | String imagePath; 35 | String videoPath; 36 | VideoPlayerController videoController; 37 | VoidCallback videoPlayerListener; 38 | WidgetsBinding widgetsBinding; 39 | Timer timer; 40 | 41 | final GlobalKey _scaffoldKey = GlobalKey(); 42 | 43 | @override 44 | void initState() { 45 | // TODO: implement initState 46 | super.initState(); 47 | if(cameras != null && !cameras.isEmpty){ 48 | onNewCameraSelected(cameras[0]); 49 | } 50 | timer = new Timer(const Duration(milliseconds: 3000), () { 51 | try { 52 | Navigator.pop(context); 53 | } catch (e) { 54 | 55 | } 56 | }); 57 | } 58 | 59 | @override 60 | Widget build(BuildContext context) { 61 | return Scaffold( 62 | key: _scaffoldKey, 63 | body: new Container( 64 | child: new Stack(children: [ 65 | new Container( 66 | child: _cameraPreviewWidget(), 67 | ), 68 | new Positioned( 69 | child: new Container( 70 | alignment: Alignment.topCenter, 71 | padding: const EdgeInsets.fromLTRB(30, 50, 30, 50), 72 | child:new Image.asset('assets/images/bg_identify_qrcode.png'), 73 | )), 74 | new Positioned( 75 | child: new Container( 76 | alignment: Alignment.bottomCenter, 77 | margin: EdgeInsets.only(bottom: 6), 78 | child: Text( 79 | '眨眨眼,点点头', 80 | style:TextStyle( 81 | color: Colors.blueAccent, 82 | fontSize: 28.0, 83 | ) 84 | ), 85 | )), 86 | ])) 87 | ); 88 | } 89 | /// Display the preview from the camera (or a message if the preview is not available). 90 | Widget _cameraPreviewWidget() { 91 | if (controller == null || !controller.value.isInitialized) { 92 | return const Text( 93 | 'Tap a camera', 94 | style: TextStyle( 95 | color: Colors.white, 96 | fontSize: 24.0, 97 | fontWeight: FontWeight.w900, 98 | ), 99 | ); 100 | } else { 101 | return AspectRatio( 102 | aspectRatio: controller.value.aspectRatio, 103 | child: CameraPreview(controller), 104 | ); 105 | } 106 | } 107 | 108 | 109 | 110 | String timestamp() => DateTime.now().millisecondsSinceEpoch.toString(); 111 | 112 | void showInSnackBar(String message) { 113 | _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message))); 114 | } 115 | 116 | void onNewCameraSelected(CameraDescription cameraDescription) async { 117 | if (controller != null) { 118 | await controller.dispose(); 119 | } 120 | controller = CameraController(cameraDescription, ResolutionPreset.high); 121 | 122 | // If the controller is updated then update the UI. 123 | controller.addListener(() { 124 | if (mounted) setState(() {}); 125 | if (controller.value.hasError) { 126 | showInSnackBar('Camera error ${controller.value.errorDescription}'); 127 | } 128 | }); 129 | 130 | try { 131 | await controller.initialize(); 132 | } on CameraException catch (e) { 133 | _showCameraException(e); 134 | } 135 | 136 | if (mounted) { 137 | setState(() {}); 138 | } 139 | } 140 | 141 | void onTakePictureButtonPressed() { 142 | takePicture().then((String filePath) { 143 | if (mounted) { 144 | setState(() { 145 | imagePath = filePath; 146 | videoController = null; 147 | videoController?.dispose(); 148 | }); 149 | if (filePath != null) { 150 | showInSnackBar('Picture saved to $filePath'); 151 | } 152 | } 153 | }); 154 | } 155 | 156 | 157 | 158 | Future takePicture() async { 159 | if (!controller.value.isInitialized) { 160 | showInSnackBar('Error: select a camera first.'); 161 | return null; 162 | } 163 | final Directory extDir = await getApplicationDocumentsDirectory(); 164 | final String dirPath = '${extDir.path}/Pictures/flutter_test'; 165 | await Directory(dirPath).create(recursive: true); 166 | final String filePath = '$dirPath/${timestamp()}.jpg'; 167 | 168 | if (controller.value.isTakingPicture) { 169 | // A capture is already pending, do nothing. 170 | return null; 171 | } 172 | 173 | try { 174 | await controller.takePicture(filePath); 175 | } on CameraException catch (e) { 176 | _showCameraException(e); 177 | return null; 178 | } 179 | return filePath; 180 | } 181 | 182 | void _showCameraException(CameraException e) { 183 | logError(e.code, e.description); 184 | showInSnackBar('Error: ${e.code}\n${e.description}'); 185 | } 186 | } 187 | 188 | 189 | List cameras; 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /lib/home/page/camera/identify_face.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:camera/camera.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:path_provider/path_provider.dart'; 7 | import 'package:video_player/video_player.dart'; 8 | import 'package:dio/dio.dart'; 9 | import 'package:flutter_app1/fast/constants/constant.dart'; 10 | import 'package:flutter_image_compress/flutter_image_compress.dart'; 11 | import 'package:path_provider/path_provider.dart' as path_provider; 12 | import 'camera_pojo.dart'; 13 | 14 | class IdentifyFace extends StatefulWidget { 15 | 16 | @override 17 | _IdentifyFaceState createState() { 18 | return _IdentifyFaceState(); 19 | } 20 | List _cameras; 21 | 22 | IdentifyFace(this._cameras){ 23 | cameras = _cameras; 24 | } 25 | } 26 | 27 | 28 | void logError(String code, String message) => 29 | print('Error: $code\nError Message: $message'); 30 | 31 | class _IdentifyFaceState extends State { 32 | CameraController controller; 33 | String imagePath; 34 | String videoPath; 35 | VideoPlayerController videoController; 36 | VoidCallback videoPlayerListener; 37 | WidgetsBinding widgetsBinding; 38 | 39 | final GlobalKey _scaffoldKey = GlobalKey(); 40 | Timer timer; 41 | @override 42 | void initState() { 43 | // TODO: implement initState 44 | super.initState(); 45 | if(cameras != null && !cameras.isEmpty){ 46 | onNewCameraSelected(cameras[1]); 47 | } 48 | timer = new Timer(const Duration(milliseconds: 3000), () { 49 | try { 50 | Navigator.pop(context); 51 | } catch (e) { 52 | 53 | } 54 | }); 55 | } 56 | 57 | @override 58 | void dispose() { 59 | timer.cancel(); 60 | super.dispose(); 61 | } 62 | 63 | @override 64 | Widget build(BuildContext context) { 65 | return Scaffold( 66 | key: _scaffoldKey, 67 | body: new Container( 68 | child: new Stack(children: [ 69 | new Container( 70 | child: _cameraPreviewWidget(), 71 | ), 72 | new Positioned( 73 | child: new Container( 74 | alignment: Alignment.topCenter, 75 | padding: const EdgeInsets.fromLTRB(30, 50, 30, 50), 76 | child:new Image.asset('assets/images/bg_identify_head.png'), 77 | )), 78 | new Positioned( 79 | child: new Container( 80 | alignment: Alignment.bottomCenter, 81 | margin: EdgeInsets.only(bottom: 6), 82 | child: Text( 83 | '眨眨眼,点点头', 84 | style:TextStyle( 85 | color: Colors.blueAccent, 86 | fontSize: 28.0, 87 | ) 88 | ), 89 | )), 90 | ])) 91 | ); 92 | } 93 | /// Display the preview from the camera (or a message if the preview is not available). 94 | Widget _cameraPreviewWidget() { 95 | if (controller == null || !controller.value.isInitialized) { 96 | return const Text( 97 | 'Tap a camera', 98 | style: TextStyle( 99 | color: Colors.white, 100 | fontSize: 24.0, 101 | fontWeight: FontWeight.w900, 102 | ), 103 | ); 104 | } else { 105 | return AspectRatio( 106 | aspectRatio: controller.value.aspectRatio, 107 | child: CameraPreview(controller), 108 | ); 109 | } 110 | } 111 | 112 | 113 | 114 | String timestamp() => DateTime.now().millisecondsSinceEpoch.toString(); 115 | 116 | void showInSnackBar(String message) { 117 | _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message))); 118 | } 119 | 120 | void onNewCameraSelected(CameraDescription cameraDescription) async { 121 | if (controller != null) { 122 | await controller.dispose(); 123 | } 124 | controller = CameraController(cameraDescription, ResolutionPreset.high); 125 | 126 | // If the controller is updated then update the UI. 127 | controller.addListener(() { 128 | if (mounted) setState(() {}); 129 | if (controller.value.hasError) { 130 | showInSnackBar('Camera error ${controller.value.errorDescription}'); 131 | } 132 | }); 133 | 134 | try { 135 | await controller.initialize(); 136 | } on CameraException catch (e) { 137 | _showCameraException(e); 138 | } 139 | 140 | if (mounted) { 141 | setState(() {}); 142 | } 143 | } 144 | 145 | void onTakePictureButtonPressed() { 146 | takePicture().then((String filePath) { 147 | if (mounted) { 148 | setState(() { 149 | imagePath = filePath; 150 | videoController = null; 151 | videoController?.dispose(); 152 | }); 153 | if (filePath != null) { 154 | showInSnackBar('Picture saved to $filePath'); 155 | } 156 | } 157 | }); 158 | } 159 | 160 | 161 | 162 | Future takePicture() async { 163 | if (!controller.value.isInitialized) { 164 | showInSnackBar('Error: select a camera first.'); 165 | return null; 166 | } 167 | final Directory extDir = await getApplicationDocumentsDirectory(); 168 | final String dirPath = '${extDir.path}/Pictures/flutter_test'; 169 | await Directory(dirPath).create(recursive: true); 170 | final String filePath = '$dirPath/${timestamp()}.jpg'; 171 | 172 | if (controller.value.isTakingPicture) { 173 | // A capture is already pending, do nothing. 174 | return null; 175 | } 176 | 177 | try { 178 | await controller.takePicture(filePath); 179 | } on CameraException catch (e) { 180 | _showCameraException(e); 181 | return null; 182 | } 183 | return filePath; 184 | } 185 | 186 | void _showCameraException(CameraException e) { 187 | logError(e.code, e.description); 188 | showInSnackBar('Error: ${e.code}\n${e.description}'); 189 | } 190 | } 191 | 192 | 193 | List cameras; 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /lib/home/page/webview/mywebview.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:camera/camera.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_app1/fast/constants/constant.dart'; 6 | import 'package:flutter_app1/home/page/camera/identify_card.dart'; 7 | import 'package:flutter_app1/home/page/camera/identify_face.dart'; 8 | import 'package:flutter_app1/home/page/camera/identify_qrcode.dart'; 9 | 10 | 11 | import 'package:webview_flutter/webview_flutter.dart'; 12 | 13 | class MyWebview extends StatefulWidget{ 14 | @override 15 | State createState() { 16 | return _MyWebviewState(); 17 | } 18 | } 19 | 20 | class _MyWebviewState extends State{ 21 | var webUrl = ""; 22 | var webUrl2; 23 | //WebViewController _Controller; 24 | final Completer _controller =Completer(); 25 | Future future_controller ; 26 | WebViewController _webViewController; 27 | Timer timer; 28 | @override 29 | void initState() { 30 | // TODO: implement initState 31 | super.initState(); 32 | getCameras(); 33 | timer = new Timer(const Duration(milliseconds: 3000), () { 34 | try { 35 | startIdentifyIDCard(context); 36 | } catch (e) { 37 | 38 | } 39 | }); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | 45 | return Scaffold( 46 | body: SafeArea( 47 | top: true, 48 | //showIDCardPage(), 49 | child: WebView( 50 | initialUrl: webUrl, 51 | javascriptMode: JavascriptMode.unrestricted, 52 | javascriptChannels: [ 53 | _alertJavascriptChannel(context), 54 | ].toSet(), 55 | 56 | onWebViewCreated: (WebViewController webViewController) { 57 | _controller.complete(webViewController); 58 | future_controller = _controller.future; 59 | }, 60 | ), 61 | ), 62 | backgroundColor: Colors.white, 63 | floatingActionButton: jsButton(), 64 | ); 65 | } 66 | Widget jsButton() { 67 | return FutureBuilder( 68 | future: _controller.future, 69 | builder: (BuildContext context, 70 | AsyncSnapshot controller) { 71 | _webViewController = controller.data; 72 | return Container(); 73 | }); 74 | } 75 | JavascriptChannel _alertJavascriptChannel(BuildContext context) { 76 | return JavascriptChannel( 77 | name: 'Flutter', 78 | onMessageReceived: (JavascriptMessage message) { 79 | if(message != null && message.message != null){ 80 | String msg = message.message; 81 | if(msg == ConstantKey.Web_Identify_Face){ 82 | startIdentifyFace(""); 83 | }else if(msg == ConstantKey.Web_Identify_IDCard){ 84 | startIdentifyIDCard(context); 85 | }else if(msg == ConstantKey.Web_Identify_QRCode){ 86 | startIdentifyQRcode(""); 87 | } 88 | } 89 | }); 90 | } 91 | /// 开始识别人脸 92 | startIdentifyFace(String message){ 93 | //startActivity(new Intent(StartWebActivity.this, IdentifyVideoActivity.class)); 94 | //Fluttertoast.showToast(msg: "开始识别人脸"); 95 | try{ 96 | Navigator.push(context, new MaterialPageRoute( 97 | builder: (BuildContext context) { 98 | return showFacePage(); 99 | })); 100 | }catch(e){ 101 | print(e.toString()); 102 | } 103 | } 104 | /// 开始识别二维码 105 | startIdentifyQRcode(String message){ 106 | //startActivity(new Intent(StartWebActivity.this, IdentifyQRcodeActivity.class)); 107 | //Fluttertoast.showToast(msg: "开始识别二维码"); 108 | try{ 109 | Navigator.push(context, new MaterialPageRoute( 110 | builder: (BuildContext context) { 111 | return showQRCodePage(); 112 | })); 113 | }catch(e){ 114 | print(e.toString()); 115 | } 116 | } 117 | /// 开始识别身份证 118 | Future startIdentifyIDCard(BuildContext context) async { 119 | Navigator.push(context, new MaterialPageRoute( 120 | builder: (BuildContext context) { 121 | /*return new MaterialApp( 122 | home:new Scaffold( 123 | body: showNextPage(), 124 | ) , 125 | );*/ 126 | return showIDCardPage(); 127 | })).then((Map result) { 128 | if(result != null){ 129 | identifyIDCardResult(result[ConstantKey.IDCARD_NUM],result[ConstantKey.IDCARD_NAME]); 130 | //print(result); 131 | } 132 | }); 133 | } 134 | showIDCardPage() { 135 | if(cameras == null || cameras.isEmpty){ 136 | getCameras(); 137 | } 138 | return new IdentifyCard(cameras); 139 | } 140 | showQRCodePage() { 141 | if(cameras == null || cameras.isEmpty){ 142 | getCameras(); 143 | } 144 | return new IdentifyQRCode(cameras); 145 | } 146 | showFacePage() { 147 | if(cameras == null || cameras.isEmpty){ 148 | getCameras(); 149 | } 150 | return new IdentifyFace(cameras); 151 | } 152 | List cameras; 153 | Future getCameras() async { 154 | // Fetch the available cameras before initializing the app. 155 | try { 156 | cameras = await availableCameras(); 157 | //FlutterImageCompress.showNativeLog = true; 158 | } on CameraException catch (e) { 159 | print(e.toString()); 160 | } 161 | } 162 | /// 发送身份证识别结果 163 | void identifyIDCardResult(var id_card,var name) { 164 | //_webViewController.evaluateJavascript("identifyIDCardResult('" + card + "','" + name + "');"); 165 | var param1 = "";var temp_card = "";var temp_name = ""; 166 | try{ 167 | temp_card = id_card;temp_name = name; 168 | param1 = "identifyIDCardResult("+'"'+temp_card+'"'+","+'"'+temp_name+'"'+");"; 169 | } catch(e){ 170 | print(e.toString()); 171 | } 172 | //var param = 'identifyIDCardResult(1407221994,"鹏华总");'; 173 | _webViewController.evaluateJavascript(param1); 174 | } 175 | @override void dispose() { 176 | // 回收相关资源 177 | super.dispose(); 178 | } 179 | 180 | } 181 | 182 | -------------------------------------------------------------------------------- /lib/start/login.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app1/fast/custom_widgets/myscrollview.dart'; 3 | import 'package:flutter_app1/start/sign_up_page.dart'; 4 | import 'package:random_pk/random_pk.dart'; 5 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 6 | import 'package:flutter_app1/start/sign_in_page.dart'; 7 | import 'package:flutter_app1/fast/utils/style.dart' as theme; 8 | 9 | class LoginPage extends StatefulWidget { 10 | LoginPage({Key key}) : super(key: key); 11 | 12 | @override 13 | _LoginPageState createState() => new _LoginPageState(); 14 | } 15 | 16 | class _LoginPageState extends State with TickerProviderStateMixin { 17 | PageController _pageController; 18 | PageView _pageView; 19 | int _currentPage = 0; 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | _pageController = new PageController(); 25 | _pageView = new PageView( 26 | controller: _pageController, 27 | children: [ 28 | new SignInPage(), 29 | new SignUpPage(), 30 | ], 31 | onPageChanged: (index) { 32 | setState(() { 33 | _currentPage = index; 34 | }); 35 | }, 36 | ); 37 | } 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | return new Scaffold( 42 | /** 43 | * SafeArea,让内容显示在安全的可见区域 44 | * SafeArea,可以避免一些屏幕有刘海或者凹槽的问题 45 | */ 46 | body: new Container( 47 | /**这里要手动设置container的高度和宽度,不然显示不了 48 | * 利用MediaQuery可以获取到跟屏幕信息有关的数据 49 | */ 50 | height: MediaQuery.of(context).size.height, 51 | width: MediaQuery.of(context).size.width, 52 | //设置渐变的背景 53 | decoration: new BoxDecoration( 54 | gradient: theme.Theme.primaryGradient, 55 | ), 56 | child:ListViewDemo( 57 | children: [ 58 | new Container( 59 | /**这里要手动设置container的高度和宽度,不然显示不了 60 | * 利用MediaQuery可以获取到跟屏幕信息有关的数据 61 | */ 62 | height: MediaQuery.of(context).size.height, 63 | width: MediaQuery.of(context).size.width, 64 | //设置渐变的背景 65 | decoration: new BoxDecoration( 66 | gradient: theme.Theme.primaryGradient, 67 | ), 68 | child: Stack(children: [ 69 | Container( 70 | height: 200, 71 | margin:EdgeInsets.only(top: 20), 72 | alignment: Alignment.center, 73 | child: Image(//顶部图片 74 | fit: BoxFit.fill, 75 | width: 270, 76 | image: new AssetImage("assets/images/login_logo.png")), 77 | ), 78 | new Column( 79 | mainAxisSize: MainAxisSize.max, 80 | children: [ 81 | new SizedBox( 82 | height: 160, 83 | ), 84 | /** 85 | * 可以用SizeBox这种写法代替Padding:在Row或者Column中单独设置一个方向的间距的时候 86 | */ 87 | // new Padding(padding: EdgeInsets.only(top: 75)), 88 | 89 | //中间的Indicator指示器 90 | new Container( 91 | width: 220, 92 | height: 42, 93 | decoration: BoxDecoration( 94 | borderRadius: BorderRadius.all(Radius.circular(25)), 95 | color: Color(0x552B2B2B), 96 | ), 97 | child: new Row( 98 | children: [ 99 | Expanded( 100 | child: new Container( 101 | /** 102 | * TODO:暂时不会用Paint去自定义indicator,所以暂时只能这样实现了 103 | */ 104 | decoration: _currentPage == 0 105 | ? BoxDecoration( 106 | borderRadius: BorderRadius.all( 107 | Radius.circular(25), 108 | ), 109 | color: Colors.white, 110 | ) 111 | : null, 112 | child: new Center( 113 | child: new FlatButton( 114 | onPressed: () { 115 | _pageController.animateToPage(0, 116 | duration: Duration(milliseconds: 500), 117 | curve: Curves.decelerate); 118 | }, 119 | child: new Text( 120 | "Existing", 121 | style: TextStyle(fontSize: 16), 122 | ), 123 | ), 124 | ), 125 | )), 126 | Expanded( 127 | child: new Container( 128 | decoration: _currentPage == 1 129 | ? BoxDecoration( 130 | borderRadius: BorderRadius.all( 131 | Radius.circular(25), 132 | ), 133 | color: Colors.white, 134 | ) 135 | : null, 136 | child: new Center( 137 | child: new FlatButton( 138 | onPressed: () { 139 | _pageController.animateToPage(1, 140 | duration: Duration(milliseconds: 500), 141 | curve: Curves.decelerate); 142 | }, 143 | child: new Text( 144 | "New", 145 | style: TextStyle(fontSize: 16), 146 | ), 147 | ), 148 | ), 149 | )), 150 | ], 151 | ), 152 | ), 153 | // new SignInPage(), 154 | // new SignUpPage(), 155 | new Expanded(child: _pageView), 156 | ], 157 | ) 158 | ],) 159 | ) 160 | ], 161 | ), 162 | ) 163 | ); 164 | } 165 | } -------------------------------------------------------------------------------- /android/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 120dp 4 | 0px 5 | 1px 6 | 2px 7 | 3px 8 | 4px 9 | 5px 10 | 6px 11 | 7px 12 | 8px 13 | 9px 14 | 10px 15 | 11px 16 | 12px 17 | 13px 18 | 14px 19 | 15px 20 | 16px 21 | 17px 22 | 18px 23 | 19px 24 | 20px 25 | 21px 26 | 22px 27 | 23px 28 | 24px 29 | 25px 30 | 26px 31 | 27px 32 | 28px 33 | 29px 34 | 30px 35 | 31px 36 | 32px 37 | 33px 38 | 34px 39 | 35px 40 | 36px 41 | 37px 42 | 38px 43 | 39px 44 | 40px 45 | 41px 46 | 42px 47 | 43px 48 | 44px 49 | 45px 50 | 46px 51 | 48px 52 | 50px 53 | 52px 54 | 55px 55 | 56px 56 | 58px 57 | 60px 58 | 64px 59 | 65px 60 | 66px 61 | 70px 62 | 71px 63 | 72px 64 | 73px 65 | 75px 66 | 76px 67 | 78px 68 | 80px 69 | 88px 70 | 90px 71 | 95px 72 | 96px 73 | 100px 74 | 104px 75 | 105px 76 | 106px 77 | 107px 78 | 110px 79 | 114px 80 | 115px 81 | 120px 82 | 122px 83 | 123px 84 | 124px 85 | 125px 86 | 126px 87 | 128px 88 | 130px 89 | 133px 90 | 135px 91 | 136px 92 | 140px 93 | 144px 94 | 148px 95 | 150px 96 | 152px 97 | 155px 98 | 160px 99 | 164px 100 | 165px 101 | 170px 102 | 172px 103 | 176px 104 | 180px 105 | 188px 106 | 192px 107 | 194px 108 | 200px 109 | 202px 110 | 204px 111 | 212px 112 | 214px 113 | 215px 114 | 218px 115 | 220px 116 | 224px 117 | 225px 118 | 228px 119 | 230px 120 | 232px 121 | 236px 122 | 240px 123 | 242px 124 | 250px 125 | 256px 126 | 260px 127 | 262px 128 | 272px 129 | 280px 130 | 284px 131 | 286px 132 | 290px 133 | 292px 134 | 296px 135 | 298px 136 | 300px 137 | 305px 138 | 320px 139 | 332px 140 | 340px 141 | 360px 142 | 348px 143 | 378px 144 | 386px 145 | 400px 146 | 406px 147 | 432px 148 | 448px 149 | 482px 150 | 500px 151 | 522px 152 | 524px 153 | 560px 154 | 580px 155 | 594px 156 | 696px 157 | 760px 158 | 796px 159 | 840px 160 | 900px 161 | 945px 162 | 1000px 163 | 1640px 164 | 54px 165 | 63px 166 | 98px 167 | 184px 168 | 185px 169 | 170 | 171 | 172 | 81px 173 | 86px 174 | 168px 175 | 222px 176 | 264px 177 | 324px 178 | 439px 179 | 459px 180 | 478px 181 | 537px 182 | 576px 183 | 608px 184 | 660px 185 | 720px 186 | 480px 187 | 489px 188 | 927px 189 | 1030px 190 | 1080px 191 | 192 | 20dp 193 | 194 | 195 | -------------------------------------------------------------------------------- /lib/fast/utils/dialog.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | import 'package:flutter_app1/fast/utils/app.dart'; 5 | import 'package:flutter_app1/fast/utils/callback.dart'; 6 | import 'package:flutter_app1/fast/utils/style.dart'; 7 | import 'package:flutter_app1/fast/utils/value.dart'; 8 | import 'package:flutter_app1/ower/sets/update.dart'; 9 | 10 | class CommonDialog{ 11 | PressedOptionCB onPressedOption; 12 | PressedSureCB onPressedSure; 13 | 14 | CommonDialog({this.onPressedOption,this.onPressedSure}); 15 | 16 | /// 展示关于APP的dialog 17 | static void showAppAboutDialog(BuildContext context) { 18 | showDialog( 19 | context: context, 20 | builder: (_) => AboutDialog( 21 | applicationName: AppHelper.app_name, 22 | applicationIcon: Image.asset('assets/images/app_logo.png'), 23 | applicationVersion: AppHelper.app_version_name, 24 | children: [ 25 | Text(AppHelper.app_introduce) 26 | ] 27 | )); 28 | } 29 | /// 展示string列表选项的simpleDialog 30 | void showOptionSimpleDialog( 31 | BuildContext context, 32 | List list) { 33 | showDialog( 34 | context: context, 35 | builder: (BuildContext context) { 36 | return SimpleDialog( 37 | children: [ 38 | ListView.builder( 39 | shrinkWrap: true,//高度自适应 40 | //physics:NeverScrollableScrollPhysics(), 41 | scrollDirection: Axis.vertical, 42 | itemCount: list.length, // item 的个数 43 | //separatorBuilder: (BuildContext context, int index) => Divider(height:1.0,color: ThemeColors.colorDDDDDD), // 添加分割线 44 | itemBuilder: (BuildContext context, int index) 45 | { 46 | return SimpleDialogOption( 47 | child: Text(list[index]), 48 | onPressed: () { 49 | Navigator.of(context).pop(); 50 | onPressedOption(list[index]); 51 | }, 52 | ); 53 | } 54 | ),], 55 | ); 56 | }, 57 | ); 58 | } 59 | /// 展示提示信息,并确定或取消 60 | void showAlertDialog(BuildContext context,String alertStr) { 61 | showDialog( 62 | context: context, 63 | barrierDismissible: false, // 表示是否点击空白区域关闭对话框,默认为true 64 | builder: (BuildContext context) { 65 | return AlertDialog( 66 | title: Container(alignment:Alignment.center,child: Text('温馨提示'),), 67 | content: SingleChildScrollView( 68 | child: ListBody( 69 | children: [ 70 | Text(alertStr), 71 | ], 72 | ), 73 | ), 74 | actions: [ 75 | FlatButton( 76 | child: Text('确定'), 77 | onPressed: () { 78 | Navigator.of(context).pop(); 79 | onPressedSure(); 80 | }, 81 | ), 82 | FlatButton( 83 | child: Text('取消',style: TextStyle(color: ThemeColors.color666666),), 84 | onPressed: () { 85 | Navigator.of(context).pop(); 86 | }, 87 | ), 88 | ], 89 | ); 90 | }, 91 | ); 92 | } 93 | /// 展示提示信息,并确定或取消 94 | void showToastDialog(BuildContext context,String alertStr) { 95 | showDialog( 96 | context: context, 97 | barrierDismissible: false, // user must tap button! 98 | builder: (BuildContext context) { 99 | return AlertDialog( 100 | content: Text(alertStr,textAlign: TextAlign.center,), 101 | actions: [ 102 | FlatButton( 103 | child: Text('确定'), 104 | onPressed: () { 105 | Navigator.of(context).pop(); 106 | }, 107 | ), 108 | ], 109 | ); 110 | }, 111 | ); 112 | } 113 | /// 自定义的APP更新提示的dialog 114 | void showCustomUpdateDialog(BuildContext context,UpdatePojo update) { 115 | showDialog( 116 | context: context, 117 | barrierDismissible: false, // user must tap button! 118 | builder: (context) { 119 | return StatefulBuilder( 120 | builder: (context, state) { 121 | return Dialog( 122 | child:Container( 123 | padding: EdgeInsets.all(16.0), 124 | child: Column( 125 | //mainAxisAlignment: MainAxisAlignment.spaceAround, 126 | mainAxisSize: MainAxisSize.min, 127 | children: [ 128 | Container( 129 | margin: EdgeInsets.only(bottom: 26), 130 | child:Text('发现新版本',textAlign: TextAlign.center,style: AppStyle.dialogKeyText3,), 131 | ), 132 | Container( 133 | margin: EdgeInsets.only(bottom: 12.0), 134 | child:Row(children: [ 135 | Text('应用 ',textAlign: TextAlign.left,style: AppStyle.dialogKeyText1), 136 | Text(AppHelper.app_name,textAlign: TextAlign.left,style: AppStyle.dialogValueText1), 137 | ],) , 138 | ), 139 | Container( 140 | margin: EdgeInsets.only(bottom: 12.0), 141 | child: Row(children: [ 142 | Text('版本 ',textAlign: TextAlign.left,style: AppStyle.dialogKeyText1), 143 | Text(update.versionName,textAlign: TextAlign.left,style: AppStyle.dialogValueText1), 144 | ],), 145 | ), 146 | Container( 147 | margin: EdgeInsets.only(bottom: 12.0), 148 | child: Row(children: [ 149 | Text('大小 ',textAlign: TextAlign.left,style: AppStyle.dialogKeyText1), 150 | Text(update.versionSize,textAlign: TextAlign.left,style: AppStyle.dialogValueText1), 151 | ],), 152 | ), 153 | Container( 154 | margin: EdgeInsets.only(bottom: 12.0), 155 | alignment: Alignment.centerLeft, 156 | child:Text('详情',style: AppStyle.dialogKeyText2), 157 | ), 158 | Container( 159 | margin: EdgeInsets.only(bottom: 12.0), 160 | child: Text(update.versionIntroduce,textAlign: TextAlign.left,style: AppStyle.dialogValueText1), 161 | ), 162 | Row(children: [ 163 | Expanded( 164 | flex: 1, 165 | child: Container( 166 | margin: EdgeInsets.only(right: 12), 167 | child: RaisedButton( 168 | shape: AppStyle.btnStyle_grey_line, 169 | onPressed: () { 170 | Navigator.of(context).pop(); 171 | }, 172 | child: Text("以后再说",style: AppStyle.buttonText2,), 173 | ), 174 | ), 175 | ), 176 | Expanded( 177 | flex: 1, 178 | child: Container( 179 | margin: EdgeInsets.only(left: 12), 180 | child: RaisedButton( 181 | color: ThemeColors.colorWhite, 182 | shape: AppStyle.btnStyle_grey_line, 183 | onPressed: () { 184 | Navigator.of(context).pop(); 185 | onPressedSure(); 186 | }, 187 | child: Text("立即更新",style: AppStyle.buttonText2,), 188 | ), 189 | ),), 190 | ],), 191 | ], 192 | ), 193 | ) 194 | 195 | ); 196 | } 197 | ); 198 | } 199 | ); 200 | } 201 | } -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | agora_rtc_engine: 5 | dependency: "direct main" 6 | description: 7 | name: agora_rtc_engine 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "0.9.4" 11 | agora_rtm: 12 | dependency: "direct main" 13 | description: 14 | name: agora_rtm 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "0.9.3" 18 | animatedloginbutton: 19 | dependency: "direct main" 20 | description: 21 | name: animatedloginbutton 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "0.1.1" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "2.0.8" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "1.0.4" 39 | camera: 40 | dependency: "direct main" 41 | description: 42 | name: camera 43 | url: "https://pub.flutter-io.cn" 44 | source: hosted 45 | version: "0.4.2" 46 | charcode: 47 | dependency: transitive 48 | description: 49 | name: charcode 50 | url: "https://pub.flutter-io.cn" 51 | source: hosted 52 | version: "1.1.2" 53 | collection: 54 | dependency: transitive 55 | description: 56 | name: collection 57 | url: "https://pub.flutter-io.cn" 58 | source: hosted 59 | version: "1.14.11" 60 | cookie_jar: 61 | dependency: transitive 62 | description: 63 | name: cookie_jar 64 | url: "https://pub.flutter-io.cn" 65 | source: hosted 66 | version: "1.0.1" 67 | cupertino_icons: 68 | dependency: "direct main" 69 | description: 70 | name: cupertino_icons 71 | url: "https://pub.flutter-io.cn" 72 | source: hosted 73 | version: "0.1.2" 74 | dio: 75 | dependency: "direct main" 76 | description: 77 | name: dio 78 | url: "https://pub.flutter-io.cn" 79 | source: hosted 80 | version: "2.1.13" 81 | english_words: 82 | dependency: "direct main" 83 | description: 84 | name: english_words 85 | url: "https://pub.flutter-io.cn" 86 | source: hosted 87 | version: "3.1.5" 88 | fluro: 89 | dependency: "direct main" 90 | description: 91 | name: fluro 92 | url: "https://pub.flutter-io.cn" 93 | source: hosted 94 | version: "1.5.0" 95 | flutter: 96 | dependency: "direct main" 97 | description: flutter 98 | source: sdk 99 | version: "0.0.0" 100 | flutter_image_compress: 101 | dependency: "direct main" 102 | description: 103 | name: flutter_image_compress 104 | url: "https://pub.flutter-io.cn" 105 | source: hosted 106 | version: "0.3.1" 107 | flutter_screenutil: 108 | dependency: "direct main" 109 | description: 110 | name: flutter_screenutil 111 | url: "https://pub.flutter-io.cn" 112 | source: hosted 113 | version: "0.5.3" 114 | flutter_spinkit: 115 | dependency: "direct main" 116 | description: 117 | name: flutter_spinkit 118 | url: "https://pub.flutter-io.cn" 119 | source: hosted 120 | version: "3.1.0" 121 | flutter_test: 122 | dependency: "direct dev" 123 | description: flutter 124 | source: sdk 125 | version: "0.0.0" 126 | flutter_webview_plugin: 127 | dependency: "direct main" 128 | description: 129 | name: flutter_webview_plugin 130 | url: "https://pub.flutter-io.cn" 131 | source: hosted 132 | version: "0.3.5" 133 | fluttertoast: 134 | dependency: "direct main" 135 | description: 136 | name: fluttertoast 137 | url: "https://pub.flutter-io.cn" 138 | source: hosted 139 | version: "2.2.11" 140 | font_awesome_flutter: 141 | dependency: "direct main" 142 | description: 143 | name: font_awesome_flutter 144 | url: "https://pub.flutter-io.cn" 145 | source: hosted 146 | version: "8.5.0" 147 | jpush_flutter: 148 | dependency: "direct main" 149 | description: 150 | name: jpush_flutter 151 | url: "https://pub.flutter-io.cn" 152 | source: hosted 153 | version: "0.0.11" 154 | like_button: 155 | dependency: "direct main" 156 | description: 157 | name: like_button 158 | url: "https://pub.flutter-io.cn" 159 | source: hosted 160 | version: "0.1.7" 161 | matcher: 162 | dependency: transitive 163 | description: 164 | name: matcher 165 | url: "https://pub.flutter-io.cn" 166 | source: hosted 167 | version: "0.12.3+1" 168 | meta: 169 | dependency: transitive 170 | description: 171 | name: meta 172 | url: "https://pub.flutter-io.cn" 173 | source: hosted 174 | version: "1.1.6" 175 | orientation: 176 | dependency: "direct main" 177 | description: 178 | name: orientation 179 | url: "https://pub.flutter-io.cn" 180 | source: hosted 181 | version: "1.0.4" 182 | path: 183 | dependency: transitive 184 | description: 185 | name: path 186 | url: "https://pub.flutter-io.cn" 187 | source: hosted 188 | version: "1.6.2" 189 | path_provider: 190 | dependency: "direct main" 191 | description: 192 | name: path_provider 193 | url: "https://pub.flutter-io.cn" 194 | source: hosted 195 | version: "0.5.0+1" 196 | pedantic: 197 | dependency: transitive 198 | description: 199 | name: pedantic 200 | url: "https://pub.flutter-io.cn" 201 | source: hosted 202 | version: "1.4.0" 203 | permission_handler: 204 | dependency: "direct main" 205 | description: 206 | name: permission_handler 207 | url: "https://pub.flutter-io.cn" 208 | source: hosted 209 | version: "3.1.0" 210 | platform: 211 | dependency: transitive 212 | description: 213 | name: platform 214 | url: "https://pub.flutter-io.cn" 215 | source: hosted 216 | version: "2.2.0" 217 | quiver: 218 | dependency: transitive 219 | description: 220 | name: quiver 221 | url: "https://pub.flutter-io.cn" 222 | source: hosted 223 | version: "2.0.1" 224 | random_pk: 225 | dependency: "direct main" 226 | description: 227 | name: random_pk 228 | url: "https://pub.flutter-io.cn" 229 | source: hosted 230 | version: "0.0.3" 231 | shared_preferences: 232 | dependency: "direct main" 233 | description: 234 | name: shared_preferences 235 | url: "https://pub.flutter-io.cn" 236 | source: hosted 237 | version: "0.5.3" 238 | sky_engine: 239 | dependency: transitive 240 | description: flutter 241 | source: sdk 242 | version: "0.0.99" 243 | source_span: 244 | dependency: transitive 245 | description: 246 | name: source_span 247 | url: "https://pub.flutter-io.cn" 248 | source: hosted 249 | version: "1.5.4" 250 | sqflite: 251 | dependency: "direct main" 252 | description: 253 | name: sqflite 254 | url: "https://pub.flutter-io.cn" 255 | source: hosted 256 | version: "1.1.6+1" 257 | stack_trace: 258 | dependency: transitive 259 | description: 260 | name: stack_trace 261 | url: "https://pub.flutter-io.cn" 262 | source: hosted 263 | version: "1.9.3" 264 | stream_channel: 265 | dependency: transitive 266 | description: 267 | name: stream_channel 268 | url: "https://pub.flutter-io.cn" 269 | source: hosted 270 | version: "1.6.8" 271 | string_scanner: 272 | dependency: transitive 273 | description: 274 | name: string_scanner 275 | url: "https://pub.flutter-io.cn" 276 | source: hosted 277 | version: "1.0.4" 278 | synchronized: 279 | dependency: transitive 280 | description: 281 | name: synchronized 282 | url: "https://pub.flutter-io.cn" 283 | source: hosted 284 | version: "2.1.0+1" 285 | term_glyph: 286 | dependency: transitive 287 | description: 288 | name: term_glyph 289 | url: "https://pub.flutter-io.cn" 290 | source: hosted 291 | version: "1.1.0" 292 | test_api: 293 | dependency: transitive 294 | description: 295 | name: test_api 296 | url: "https://pub.flutter-io.cn" 297 | source: hosted 298 | version: "0.2.2" 299 | typed_data: 300 | dependency: transitive 301 | description: 302 | name: typed_data 303 | url: "https://pub.flutter-io.cn" 304 | source: hosted 305 | version: "1.1.6" 306 | vector_math: 307 | dependency: transitive 308 | description: 309 | name: vector_math 310 | url: "https://pub.flutter-io.cn" 311 | source: hosted 312 | version: "2.0.8" 313 | video_player: 314 | dependency: "direct main" 315 | description: 316 | name: video_player 317 | url: "https://pub.flutter-io.cn" 318 | source: hosted 319 | version: "0.10.0+4" 320 | webview_flutter: 321 | dependency: "direct main" 322 | description: 323 | name: webview_flutter 324 | url: "https://pub.flutter-io.cn" 325 | source: hosted 326 | version: "0.3.9" 327 | sdks: 328 | dart: ">=2.1.0 <3.0.0" 329 | flutter: ">=1.2.1 <2.0.0" 330 | -------------------------------------------------------------------------------- /lib/start/like_button_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:like_button/like_button.dart'; 3 | 4 | /// 5 | /// create by zhoumaotuo on 2019/5/27 6 | /// 7 | 8 | const double buttonSize = 40.0; 9 | 10 | class LikeButtonDemo extends StatefulWidget { 11 | @override 12 | _LikeButtonDemoState createState() => _LikeButtonDemoState(); 13 | } 14 | 15 | class _LikeButtonDemoState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | final int likeCount = 999; 19 | return Material( 20 | child: Column(children: [ 21 | AppBar( 22 | title: Text("Like Button Demo"), 23 | ), 24 | Expanded( 25 | child: GridView( 26 | children: [ 27 | new LikeButton( 28 | size: buttonSize, 29 | likeCount: likeCount, 30 | countBuilder: (int count, bool isLiked, String text) { 31 | var color = isLiked ? Colors.pinkAccent : Colors.grey; 32 | Widget result; 33 | if (count == 0) { 34 | result = Text( 35 | "love", 36 | style: TextStyle(color: color), 37 | ); 38 | } else 39 | result = Text( 40 | count >= 1000 41 | ? (count / 1000.0).toStringAsFixed(1) + "k" 42 | : text, 43 | style: TextStyle(color: color), 44 | ); 45 | return result; 46 | }, 47 | likeCountAnimationType: likeCount < 1000 48 | ? LikeCountAnimationType.part 49 | : LikeCountAnimationType.none, 50 | likeCountPadding: EdgeInsets.only(left: 15.0), 51 | ), 52 | new LikeButton( 53 | size: buttonSize, 54 | circleColor: 55 | CircleColor(start: Color(0xff00ddff), end: Color(0xff0099cc)), 56 | bubblesColor: BubblesColor( 57 | dotPrimaryColor: Color(0xff33b5e5), 58 | dotSecondaryColor: Color(0xff0099cc), 59 | ), 60 | likeBuilder: (bool isLiked) { 61 | return Icon( 62 | Icons.home, 63 | color: isLiked ? Colors.deepPurpleAccent : Colors.grey, 64 | size: buttonSize, 65 | ); 66 | }, 67 | likeCount: 665, 68 | countBuilder: (int count, bool isLiked, String text) { 69 | var color = isLiked ? Colors.deepPurpleAccent : Colors.grey; 70 | Widget result; 71 | if (count == 0) { 72 | result = Text( 73 | "love", 74 | style: TextStyle(color: color), 75 | ); 76 | } else 77 | result = Text( 78 | text, 79 | style: TextStyle(color: color), 80 | ); 81 | return result; 82 | }, 83 | likeCountPadding: EdgeInsets.only(left: 15.0), 84 | ), 85 | new LikeButton( 86 | size: buttonSize, 87 | circleColor: 88 | CircleColor(start: Color(0xff669900), end: Color(0xff669900)), 89 | bubblesColor: BubblesColor( 90 | dotPrimaryColor: Color(0xff669900), 91 | dotSecondaryColor: Color(0xff99cc00), 92 | ), 93 | likeBuilder: (bool isLiked) { 94 | return Icon( 95 | Icons.adb, 96 | color: isLiked ? Colors.green : Colors.grey, 97 | size: buttonSize, 98 | ); 99 | }, 100 | likeCount: 665, 101 | likeCountAnimationType: LikeCountAnimationType.all, 102 | countBuilder: (int count, bool isLiked, String text) { 103 | var color = isLiked ? Colors.green : Colors.grey; 104 | Widget result; 105 | if (count == 0) { 106 | result = Text( 107 | "love", 108 | style: TextStyle(color: color), 109 | ); 110 | } else 111 | result = Text( 112 | text, 113 | style: TextStyle(color: color), 114 | ); 115 | return result; 116 | }, 117 | likeCountPadding: EdgeInsets.only(left: 15.0), 118 | ), 119 | new LikeButton( 120 | size: buttonSize, 121 | isLiked: null, 122 | circleColor: CircleColor( 123 | start: Colors.redAccent[100], 124 | end: Colors.redAccent[400], 125 | ), 126 | bubblesColor: BubblesColor( 127 | dotPrimaryColor: Colors.red[300], 128 | dotSecondaryColor: Colors.red[200], 129 | ), 130 | likeBuilder: (bool isLiked) { 131 | return Icon( 132 | Icons.assistant_photo, 133 | color: Colors.red, 134 | size: buttonSize, 135 | ); 136 | }, 137 | likeCount: 888, 138 | countBuilder: (int count, bool isLiked, String text) { 139 | var color = Colors.red; 140 | Widget result; 141 | if (count == 0) { 142 | result = Text( 143 | "love", 144 | style: TextStyle(color: color), 145 | ); 146 | } else 147 | result = Text( 148 | text, 149 | style: TextStyle(color: color), 150 | ); 151 | return result; 152 | }, 153 | likeCountPadding: EdgeInsets.only(left: 15.0), 154 | ), 155 | new LikeButton( 156 | size: buttonSize, 157 | circleColor: CircleColor( 158 | start: Colors.pinkAccent[200], end: Colors.pinkAccent[400]), 159 | bubblesColor: BubblesColor( 160 | dotPrimaryColor: Colors.lightBlue[300], 161 | dotSecondaryColor: Colors.lightBlue[200], 162 | ), 163 | likeBuilder: (bool isLiked) { 164 | return Icon( 165 | Icons.insert_emoticon, 166 | color: isLiked ? Colors.lightBlueAccent : Colors.grey, 167 | size: buttonSize, 168 | ); 169 | }, 170 | ), 171 | new LikeButton( 172 | size: buttonSize, 173 | isLiked: null, 174 | circleColor: CircleColor( 175 | start: Colors.grey[200], 176 | end: Colors.grey[400], 177 | ), 178 | bubblesColor: BubblesColor( 179 | dotPrimaryColor: Colors.grey[600], 180 | dotSecondaryColor: Colors.grey[200], 181 | ), 182 | likeBuilder: (bool isLiked) { 183 | return Icon( 184 | Icons.cloud, 185 | color: isLiked ? Colors.grey[900] : Colors.grey, 186 | size: buttonSize, 187 | ); 188 | }, 189 | likeCount: 888, 190 | postion: Postion.left, 191 | countBuilder: (int count, bool isLiked, String text) { 192 | var color = Colors.grey; 193 | Widget result; 194 | if (count == 0) { 195 | result = Text( 196 | "love", 197 | style: TextStyle(color: color), 198 | ); 199 | } else 200 | result = Text( 201 | text, 202 | style: TextStyle(color: color), 203 | ); 204 | return result; 205 | }, 206 | likeCountPadding: EdgeInsets.only(right: 15.0), 207 | ), 208 | new LikeButton( 209 | size: buttonSize, 210 | isLiked: false,//true-默认展示为彩色喜欢状态,false-默认展示位灰色不喜欢,null-默认彩色且每次点击都有动画 211 | /*circleColor: CircleColor(start: Color(0xFFFF3030), end: Color(0xFF008000)), 212 | bubblesColor:BubblesColor( 213 | dotPrimaryColor: Color(0xFF2F4F4F), dotSecondaryColor: Color(0xFF7B68EE), 214 | dotThirdColor: Color(0xFF0000FF),dotLastColor:Color(0xFFC71585) ),*/ 215 | circleColor: CircleColor(start: Color(0xFFFF8321), end: Color(0xFFFF5722)), 216 | bubblesColor:BubblesColor( 217 | dotPrimaryColor: Color(0xFFF5642C ), dotSecondaryColor: Color(0xFFFFA500), 218 | dotThirdColor: Color(0xFFF5642C),dotLastColor:Color(0xFFFFA500) ), 219 | animationDuration:Duration(milliseconds: 1000), 220 | likeCount: 888, 221 | likeBuilder: (bool isLiked) { 222 | return Icon( 223 | Icons.thumb_up, 224 | color: isLiked ? Colors.deepOrange : Colors.grey, 225 | size: buttonSize, 226 | ); 227 | }, 228 | likeCountPadding: EdgeInsets.only(left: 15.0), 229 | ), 230 | //new AnimatedLoginButton, 231 | ], 232 | gridDelegate: 233 | SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), 234 | ), 235 | ) 236 | ])); 237 | } 238 | } 239 | --------------------------------------------------------------------------------